C# 为什么我的getter会被调用,直到出现堆栈溢出?

C# 为什么我的getter会被调用,直到出现堆栈溢出?,c#,linq,json.net,getter,accessor,C#,Linq,Json.net,Getter,Accessor,我在我的Winforms应用程序中使用了一个通用列表,在整个代码中,我将首先检查底层json文件是否存在,如果存在,将其反序列化,然后访问反序列化的通用列表。我决定最好将代码放在一个地方,因此: public static List<AssignmentHistory> assignmentHistList { get { return GetAssignmentHistoryList(); } } public static List<AssignmentHisto

我在我的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;
}
…但永远不要超出该行,因为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;
}
assignmentHistList属性的getter调用GetAssignmentHistoryList,后者递归调用assignmentHistList属性的getter

goto Label1;
您可能希望将该属性称为AssignmentHistList,并使用大写字母A,符合常见的代码样式实践,并且具有私有静态字段AssignmentHistList。无论如何,属性X和GetX方法的双重性是存在的。

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

只有通过观察下面的代码,我们才能推断出它们是一个visious循环调用

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
}

因为您的代码失败的原因已经有了答案,所以我想发布一个可能的代码修复程序:

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

请记住,如果应该从中反序列化的文件不存在,这将引发ArgumentNullException。

是否看到assignmentHistList和GetAssignmentHistoryList之间的循环引用?使用调试器逐步调试它,您将看到在这两者之间不断切换。在GetAssignmentHistoryList中,您返回assignmentHistList属性,该属性本身返回GetAssignmentHistoryList的结果。GetAssignmentHistoryList读取属性assignmentHistList,它的get函数调用GetAssignmentHistoryList。如果你用F11一步一步地看代码,这应该是显而易见的。goto的一个罕见的好用法,可能是。@Quetzalcatl我真的很喜欢在过去的20年左右第一次将它用于实际目的:D注到B。Clay Shannon:很可能不是小写赋值HistList getter only属性,您希望为大写的GetAssignment提供一个简单的支持字段…-我的意思是:私有静态列表分配HistList;。另外,我注意到您正试图在GetAssignment中实现延迟初始化…-为此,您需要更改return DeserializeAssignmentHistFile;to assignmentHistList=反序列化AssignmentHistFile;返回赋值历史列表;谢谢你,阿博托;我想给你一笔赏金,但除非这个问题重新开始,否则这是不可能的。。。
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
}
// 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);