我想知道你是否可以查看我的代码,看看我哪里出错了。基本上,我创建了一个“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();
}
}
}
答案 0 :(得分:3)
问题是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!
这里发生的是成员变量fileIndividuals
,fileFamilies
和fileHead
设置为individuals
的{strong>引用,{{1静态families
类上的{}和head
属性,不是副本(因为它们是类而不是值类型)。因此,下次ReadFromFile
被调用时,ReadFromFile.Read()
上的静态属性会被更新(覆盖),但ReadFromFile
的先前实例只指向相同的静态属性,ergo UserFile
和file1
将拥有相同的数据。
那你怎么解决这个问题呢?两个选项:
file2
和实例类,而不是静态类。在ReadFromFile
构造函数中构造一个新实例,不要使用任何静态属性。UserFile
的构造函数中复制individuals
,families
和head
中的数据。通过每个项目“foreach”,并将其复制到新词典中。 简单说明:
如果对象是类,则执行assign(C#中的=字符)时,会为目标指定右侧的“指针”(引用)。如果它是值类型,则复制它。 Dictionary是一个类,所以你得到一个指针,而不是一个副本。
代码中的插图:
UserFile
...别处
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
时,我们没有获得该项目的副本,只有参考。