Экземпляр объекта перезаписывает другой экземпляр, но я не понимаю, почему - PullRequest
1 голос
/ 27 марта 2012

Мне было интересно, не могли бы вы взглянуть на мой код и увидеть, где я ошибся.По сути, я создал объект типа «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);
        }
    }

Вот файл пользователякласс с конструктором

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

Вот метод ReadFromFile, вызываемый классом UserFile

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

1 Ответ

3 голосов
/ 27 марта 2012

Проблема заключается в следующих статических свойствах класса 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 об использовании статических свойств.

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

Что здесь происходит, так это переменные-члены fileIndividuals, fileFamilies и fileHeadна ссылку свойств individuals, families и head на статический класс ReadFromFile, не копию (так как они являются классами, а не типами значений),Поэтому в следующий раз, когда ReadFromFile.Read() вызывается, статические свойства ReadFromFile обновляются (перезаписываются), но предыдущий экземпляр UserFile просто указывает на те же самые статические свойства, следовательно file1 и file2 будет иметь те же данные.

Так как бы это исправить?Два варианта:

  1. Сделать ReadFromFile и экземпляр класса, а не статический.Создайте новый экземпляр в конструкторе UserFile и не используйте любые статические свойства.
  2. Создайте копию данных в individuals, families и head вконструктор UserFile."foreach" через каждый элемент и скопируйте его в новый словарь.

Простое объяснение:

Когда вы выполняете присваивание (символ = в C #), если объект является классом, тогда цели присваивается «указатель» (ссылка) на правой стороне.Если это тип значения, он копируется.Словарь - это класс, поэтому вы получаете указатель, а не копию.

Иллюстрация в коде:

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.Ну myList1 и myList2 указывают на одно и то же.Когда мы сделали myList1 = MyStaticClass.MyList, мы не получили копию предмета, просто ссылку на него.

...