为什么我的 getter 在出现 StackOverflow 之前一直被调用?
Why is my getter being called until there is a StackOverflow?
我在我的 Winforms 应用程序中使用了一个通用列表,并且在整个代码中我首先检查底层 (json) 文件是否存在,如果存在,反序列化它,然后访问反序列化的通用列表。我决定将代码放在一个地方会更好,所以这样做:
public static List<AssignmentHistory> assignmentHistList
{
get { return GetAssignmentHistoryList(); }
}
public static List<AssignmentHistory> GetAssignmentHistoryList()
{
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME)) return null;
if (null == assignmentHistList)
{
return DeserializeAssignmentHistFile();
}
return assignmentHistList;
}
public static List<AssignmentHistory> DeserializeAssignmentHistFile()
{
var assignmentHistFile = System.IO.File.ReadAllText(ASSIGNMENT_HISTORY_FILENAME);
var assignmentHistDeserialized = JsonConvert.DeserializeObject<List<AssignmentHistory>>(assignmentHist);
return assignmentHistDeserialized;
}
然后我这样称呼它:
AssignmentHistory ah =
AYttFMConstsAndUtils.assignmentHistList.FirstOrDefault(
i => i.WeekOfAssignment == currentWeek && i.TalkType == 1);
...但永远不要超出那条线,因为 GetAssignmentHistoryList() 会被一遍又一遍地调用,直到出现堆栈溢出。我在这里做错了什么?
更新
我使用了 abto 的 null 合并运算符建议,但为了防止空文件的可能性,我还必须修改我的反序列化方法,现在是:
private static List<AssignmentHistory> DeserializeAssignmentHistFile()
{
List<AssignmentHistory> assignmentHistoryList;
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME))
{
var assignmentFile = System.IO.File.Create(ASSIGNMENT_HISTORY_FILENAME);
assignmentFile.Close();
}
var assignmentHistFile = System.IO.File.ReadAllText(ASSIGNMENT_HISTORY_FILENAME);
var assignmentHistDeserialized = JsonConvert.DeserializeObject<List<AssignmentHistory>>(assignmentHistFile);
if (null != assignmentHistDeserialized) return assignmentHistDeserialized;
assignmentHistoryList = new List<AssignmentHistory>();
return assignmentHistoryList;
}
Label1:
assignmentHistList
属性 的 getter 调用 GetAssignmentHistoryList()
,后者递归调用 assignmentHistList
属性 的 getter。
goto Label1;
您可能希望 属性 被称为 AssignmentHistList
,大写 A
,符合通用代码风格惯例,并具有私有静态字段 assignmentHistList
。无论如何,属性 X
和 GetX()
方法存在的双重性很奇怪。
Whosebug 异常通常是由于未正确检测到递归调用条件而发生的。
只有观察下面的代码,我们才能推断出它们是一个视觉循环调用。
assignmentHistList -> GetAssignmentHistoryList,检查条件 null == assignmentHistList
但是为了检查这个条件它需要输入(递归)再次用于 assignmentHistList,然后将再次调用 GetAssignmentHistoryList。你可以看到这是怎么回事。
public static List<AssignmentHistory> assignmentHistList
{
get { return GetAssignmentHistoryList(); }
}
public static List<AssignmentHistory> GetAssignmentHistoryList()
{
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME)) return null;
if (null == assignmentHistList) << Here is another call to the Getter
// The rest is not important
}
因为您的代码失败的原因已经有了答案,我想 post 对您的代码进行可能的修复:
// this is the backing field for your property
private static List<AssignmentHistory> assignmentHistList;
// it is good practice to name properties starting uppercase
public static List<AssignmentHistory> AssignmentHistList
{
get
{
// return the content of the backing field if is not null
return assignmentHistList ??
// in case the backing field is null,
// assign it a value from your deserialize method
// and than return it
(assignmentHistList = DeserializeAssignmentHistFile());
}
}
private static List<AssignmentHistory> DeserializeAssignmentHistFile()
{
// If the file which should contain your data does not exist (yet) return null,
// the property will retry to set the backing field the next time it is accessed
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME)) return null;
var assignmentHistFile
= System.IO.File.ReadAllText(ASSIGNMENT_HISTORY_FILENAME);
var assignmentHistDeserialized
= JsonConvert.DeserializeObject<List<AssignmentHistory>>(assignmentHist);
return assignmentHistDeserialized;
}
然后你可以(大部分)按照你想要的方式调用它:
AssignmentHistory ah = AYttFMConstsAndUtils.AssignmentHistList
.FirstOrDefault(i => i.WeekOfAssignment == currentWeek && i.TalkType == 1);
请记住,如果应反序列化的文件不存在,这将抛出 ArgumentNullException
。
我在我的 Winforms 应用程序中使用了一个通用列表,并且在整个代码中我首先检查底层 (json) 文件是否存在,如果存在,反序列化它,然后访问反序列化的通用列表。我决定将代码放在一个地方会更好,所以这样做:
public static List<AssignmentHistory> assignmentHistList
{
get { return GetAssignmentHistoryList(); }
}
public static List<AssignmentHistory> GetAssignmentHistoryList()
{
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME)) return null;
if (null == assignmentHistList)
{
return DeserializeAssignmentHistFile();
}
return assignmentHistList;
}
public static List<AssignmentHistory> DeserializeAssignmentHistFile()
{
var assignmentHistFile = System.IO.File.ReadAllText(ASSIGNMENT_HISTORY_FILENAME);
var assignmentHistDeserialized = JsonConvert.DeserializeObject<List<AssignmentHistory>>(assignmentHist);
return assignmentHistDeserialized;
}
然后我这样称呼它:
AssignmentHistory ah =
AYttFMConstsAndUtils.assignmentHistList.FirstOrDefault(
i => i.WeekOfAssignment == currentWeek && i.TalkType == 1);
...但永远不要超出那条线,因为 GetAssignmentHistoryList() 会被一遍又一遍地调用,直到出现堆栈溢出。我在这里做错了什么?
更新
我使用了 abto 的 null 合并运算符建议,但为了防止空文件的可能性,我还必须修改我的反序列化方法,现在是:
private static List<AssignmentHistory> DeserializeAssignmentHistFile()
{
List<AssignmentHistory> assignmentHistoryList;
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME))
{
var assignmentFile = System.IO.File.Create(ASSIGNMENT_HISTORY_FILENAME);
assignmentFile.Close();
}
var assignmentHistFile = System.IO.File.ReadAllText(ASSIGNMENT_HISTORY_FILENAME);
var assignmentHistDeserialized = JsonConvert.DeserializeObject<List<AssignmentHistory>>(assignmentHistFile);
if (null != assignmentHistDeserialized) return assignmentHistDeserialized;
assignmentHistoryList = new List<AssignmentHistory>();
return assignmentHistoryList;
}
Label1:
assignmentHistList
属性 的 getter 调用 GetAssignmentHistoryList()
,后者递归调用 assignmentHistList
属性 的 getter。
goto Label1;
您可能希望 属性 被称为 AssignmentHistList
,大写 A
,符合通用代码风格惯例,并具有私有静态字段 assignmentHistList
。无论如何,属性 X
和 GetX()
方法存在的双重性很奇怪。
Whosebug 异常通常是由于未正确检测到递归调用条件而发生的。
只有观察下面的代码,我们才能推断出它们是一个视觉循环调用。
assignmentHistList -> GetAssignmentHistoryList,检查条件 null == assignmentHistList
但是为了检查这个条件它需要输入(递归)再次用于 assignmentHistList,然后将再次调用 GetAssignmentHistoryList。你可以看到这是怎么回事。
public static List<AssignmentHistory> assignmentHistList
{
get { return GetAssignmentHistoryList(); }
}
public static List<AssignmentHistory> GetAssignmentHistoryList()
{
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME)) return null;
if (null == assignmentHistList) << Here is another call to the Getter
// The rest is not important
}
因为您的代码失败的原因已经有了答案,我想 post 对您的代码进行可能的修复:
// this is the backing field for your property
private static List<AssignmentHistory> assignmentHistList;
// it is good practice to name properties starting uppercase
public static List<AssignmentHistory> AssignmentHistList
{
get
{
// return the content of the backing field if is not null
return assignmentHistList ??
// in case the backing field is null,
// assign it a value from your deserialize method
// and than return it
(assignmentHistList = DeserializeAssignmentHistFile());
}
}
private static List<AssignmentHistory> DeserializeAssignmentHistFile()
{
// If the file which should contain your data does not exist (yet) return null,
// the property will retry to set the backing field the next time it is accessed
if (!System.IO.File.Exists(ASSIGNMENT_HISTORY_FILENAME)) return null;
var assignmentHistFile
= System.IO.File.ReadAllText(ASSIGNMENT_HISTORY_FILENAME);
var assignmentHistDeserialized
= JsonConvert.DeserializeObject<List<AssignmentHistory>>(assignmentHist);
return assignmentHistDeserialized;
}
然后你可以(大部分)按照你想要的方式调用它:
AssignmentHistory ah = AYttFMConstsAndUtils.AssignmentHistList
.FirstOrDefault(i => i.WeekOfAssignment == currentWeek && i.TalkType == 1);
请记住,如果应反序列化的文件不存在,这将抛出 ArgumentNullException
。