【问题标题】:Object instance is overwriting the other instance but I cant see why对象实例正在覆盖另一个实例,但我不明白为什么
【发布时间】:2012-04-10 11:58:04
【问题描述】:

我想知道您是否可以查看我的代码,看看我哪里出错了。基本上,我创建了一个类型为“UserFile”(我自己的对象类型)的对象,并创建了它的 2 个实例,并且在该对象的构造函数中,我调用了一个静态类方法。除了第二个实例在调用对象构造函数后覆盖第一个实例外,一切对他们来说都很顺利。我已经完成了这个程序并且完全感到困惑。我觉得我在这里遗漏了一些非常明显的东西。

这是创建实例的表单上的按钮

    private void btnCompare_Click(object sender, EventArgs e)
    {
        if (lstFiles.CheckedItems.Count == 2)
        {
            file1 = new UserFile(((FileLocation)lstFiles.CheckedItems[0]).filePath);

            file2 = new UserFile(((FileLocation)lstFiles.CheckedItems[1]).filePath);
        }
    }

这是带有构造函数的 UserFile 类

public class UserFile
{
    public Dictionary<int,Individual> fileIndividuals;
    public Dictionary<int, Family> fileFamilies;
    public Header fileHead;

    public UserFile(string _dir)
    {
        fileIndividuals = new Dictionary<int, Individual>();
        fileFamilies = new Dictionary<int, Family>();
        fileHead = new Header();
        ReadFromFile.Read(_dir);
        fileIndividuals = ReadFromFile.individuals;
        fileFamilies = ReadFromFile.families;
        fileHead = ReadFromFile.head;
    }
}

这里是 UserFile 类调用的 ReadFromFile 方法

static class ReadFromFile
{
    public static string filename = "";

    public static Header head;
    public static Individual individual;
    public static Dictionary<int, Individual> individuals = new Dictionary<int, Individual>();

    public static Family family;
    public static Dictionary<int, Family> families = new Dictionary<int, Family>();

    public static GedcomRecordEnum currentRecord = GedcomRecordEnum.None;
    public static GedcomSubRecordEnum currentFirstLvlRecord = GedcomSubRecordEnum.None;
    public static GedcomSecondLevelEnum currentSecondLvlRecord = GedcomSecondLevelEnum.None;

    static public void Read(string fileName)
    {
        individuals.Clear();
        families.Clear();
        head = null;
        if (File.Exists(fileName))
        {
            filename = fileName;
            StreamReader reader = new StreamReader(fileName);

            while (!reader.EndOfStream)
            {
                string currentLine = reader.ReadLine();
                Match m = Regex.Match(currentLine, "(?<index>[0-9]) (?<keyword>[A-Z_@0-9]+)(?: *)(?<detail>.*)");

                string debug = m.Groups["index"].ToString();

                switch (m.Groups["index"].ToString())
                {
                    case "0":
                        ProcessRootLevel(m.Groups["keyword"].ToString());
                        break;
                    case "1":
                        ProcessLevel1(m.Groups["keyword"].ToString(), m.Groups["detail"].ToString());
                        break;
                    case "2":
                        ProcessLevel2(m.Groups["keyword"].ToString(), m.Groups["detail"].ToString());
                        break;
                    case "3":
                        ProcessLevel3(m.Groups["keyword"].ToString(), m.Groups["detail"].ToString());
                        break;
                }
            }
            reader.Close();
        }
    }
}

【问题讨论】:

    标签: c# object constructor instances


    【解决方案1】:

    问题是ReadFromFile 类的以下静态属性,如果我假设“覆盖”你的意思是UserFile 的两个实例都指向相同的数据:

     public static Dictionary<int, Family> families = new Dictionary<int, Family>();
     public static Dictionary<int, Individual> individuals = new Dictionary<int, Individual>();
     public static Header head;
    

    问题在于UserFile的构造函数对static属性的使用。

        ReadFromFile.Read(_dir);
        fileIndividuals = ReadFromFile.individuals; // <-- Uh-oh!
        fileFamilies = ReadFromFile.families;       // <-- Uh-oh!
        fileHead = ReadFromFile.head;               // <-- Uh-oh!
    

    这里发生的情况是成员变量fileIndividualsfileFamiliesfileHead 被设置为静态上individualsfamilieshead 属性的引用 ReadFromFile 类,不是副本(因为它们是类而不是值类型)。因此,下次调用 ReadFromFile.Read() 时,ReadFromFile 上的静态属性将被更新(覆盖),但 UserFile 的先前实例仅指向 same 静态属性,因此 file1file2 将具有相同的数据。

    那么你将如何解决这个问题?两种选择:

    1. 创建ReadFromFile 和实例类,而不是静态类。在UserFile 构造函数中构造一个新实例,并且不要使用任何静态属性。
    2. UserFile的构造函数中复制individualsfamilieshead中的数据。 “foreach”遍历每个项目,并将其复制到新字典中。

    简单解释:

    如果对象是类,则当您执行分配(C# 中的 = 字符)时,目标会被分配一个指向右侧的“指针”(引用)。如果它是一个值类型,它会被复制。 Dictionary 是一个类,所以你得到一个指针而不是副本。

    代码说明:

    public static class MyStaticClass
    {
         public static List<string> MyList = new List<string> 
    }
    

    其他地方...

    public void MyMethod()
    {
        List<string> myList1 = MyStaticClass.MyList; 
        List<string> myList2 = MyStaticClass.MyList; 
    
        myList1.Add("Hello");  // Add to first list
        myList2.Add("World");  // Add to second list 
    
        foreach(string item in myList1) // print all items in the second list
        {
             Console.WriteLine("List 1: " + item); 
        }
    
        foreach(string item in myList2) // print all items in the second list
        {
             Console.WriteLine("List 2: " + item); 
        }
    } 
    

    这个输出将是:

    List 1: Hello
    List 1: World
    List 2: Hello
    List 2: World 
    

    但是为什么呢?我们只在myList2 中添加了“世界”。 myList1myList2 指向 是同一件事。当我们执行myList1 = MyStaticClass.MyList 时,我们没有得到该项目的副本,只是对它的引用

    【讨论】:

    • 谢谢你,但我想知道你能不能用更基本的术语解释一下?我正在考虑第二种选择
    • 完成 :) 顺便说一句,你真的想要选项 #1。
    • 我知道,但是当我停止 ReadFromFile 类是静态的时,没有任何效果。我忘记了我现在将其设为静态的原因
    • 谢谢你UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU!!!!!!!!!!我已经注释掉了 UserFile 构造函数中的 3 行,它们使事情变得“哦”。谢谢!
    猜你喜欢
    • 2012-09-27
    • 2013-07-02
    • 2013-04-20
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    相关资源
    最近更新 更多