为什么我的 getter 被调用,直到有一个 StackOverflow

本文关键字:有一个 StackOverflow 调用 我的 getter 为什么 | 更新日期: 2023-09-27 18:35:38

我在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 的空合并运算符建议,但为了防止空文件的可能性,我还必须修改我的反序列化方法,以便现在:

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;
}

为什么我的 getter 被调用,直到有一个 StackOverflow

因为已经有答案为什么你的代码失败,我想发布一个可能的代码修复:

// 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

Label1:

assignmentHistList属性的 getter 调用GetAssignmentHistoryList()assignmentHistList属性的 getter 递归调用。

goto Label1;

您可能希望使用大写A调用该属性AssignmentHistList,与常见的代码样式做法保持一致,并具有私有静态字段assignmentHistList。无论如何,属性XGetX()方法存在的双重性是奇怪的。

堆栈溢出异常通常是由于未正确检测到递归调用条件而发生的。

只有观察下面的代码,我们才能推断出存在一个恶性循环调用。

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
}