IList.Add() 覆盖现有数据

6
我遇到了一个问题,想向一个 IList 添加数据,但每次添加数据时,现有的数据都会被当前的数据覆盖。我的代码如下:
Test test = new Test();
IList<Test> myList = new List<Test>();

foreach (DataRow dataRow in dataTable.Rows)
{
     test.PatientID = Convert.ToInt64(dataRow.ItemArray[0]);
     test.LastName = dataRow.ItemArray[1].ToString();
     test.FirstName = dataRow.ItemArray[2].ToString();
     myList.Add(test);
}

这背后的原因是什么?

http://msdn.microsoft.com/en-us/library/490f96s2.aspx - ta.speot.is
2
你遇到的问题是test是一个引用类型而不是值类型,当你将test添加到列表中时,你实际上是添加了指向test所在内存的指针。当你运行下一个循环时,你会在该内存空间中进行更改,覆盖上一个循环的数据。因此,在循环内部你需要使用New语句来为该循环分配新的内存空间。 - MikeT
2
这是一个常见的错误,人们需要一些时间来理解这个概念,可以将其想象成拥有一个文件柜,有两种使用文件柜的方式:你可以把一张纸放在里面,上面写着所有的数据(这是值类型),或者你可以把一张纸放在里面,上面写着如何定位存储在其他地方的原始纸张的指令(引用类型)。在这种情况下,您正在添加许多带有说明的纸张副本,但始终对原始纸张进行更改。新语句告诉它为您获取一张新的纸张以使用。 - MikeT
6个回答

13

将测试对象的创建移到循环内部

IList<Test> myList = new List<Test>();

foreach (DataRow dataRow in dataTable.Rows)
{   Test test =new Test();
    test.PatientID = Convert.ToInt64(dataRow.ItemArray[0]);
    test.LastName = dataRow.ItemArray[1].ToString();
    test.FirstName = dataRow.ItemArray[2].ToString();
    myList.Add(test);
 }

你目前正在循环中更新相同的test实例,并且一遍又一遍地添加相同的实例。


4

您需要将Test对象的创建移到循环内部。原因是new Test()对象只被实例化一次,并且对同一对象的引用会持续添加到循环中的列表中。


3

因为Test test是按引用复制的,所以你需要将它放在循环内部。

像这样做:

IList<Test> myList = new List<Test>();
foreach (DataRow dataRow in dataTable.Rows)
{
     Test test =new Test();
     test.PatientID = Convert.ToInt64(dataRow.ItemArray[0]);
     test.LastName = dataRow.ItemArray[1].ToString();
     test.FirstName = dataRow.ItemArray[2].ToString();
     myList.Add(test);
}

2

你一直在使用同一个引用变量(test)。尝试在循环中创建新的Test()。


2

因为您在foreach循环中没有创建新的实例,所以请更正代码:

Test test = null;
IList<Test> myList = new List<Test>();

foreach (DataRow dataRow in dataTable.Rows)
{
   test = new Test();
   test.PatientID = Convert.ToInt64(dataRow.ItemArray[0]);
   test.LastName = dataRow.ItemArray[1].ToString();
   test.FirstName = dataRow.ItemArray[2].ToString();
   myList.Add(test);
}

2
您正在创建一个Test的单个实例。
Test test = new Test(); // This is your instance
IList<Test> myList = new List<Test>();

foreach (DataRow dataRow in dataTable.Rows)
{
    // Here you change the values of the existing instance each time you loop
    test.PatientID = Convert.ToInt64(dataRow.ItemArray[0]);
    test.LastName = dataRow.ItemArray[1].ToString();
    test.FirstName = dataRow.ItemArray[2].ToString();
    myList.Add(test); // but you are still just adding the same reference to the list multiple times
}

由于您从未创建新的Test实例,因此您多次将相同的引用添加到列表中。这意味着您基本上只是重复存储相同的对象:如果您对列表中的一个项目进行任何更改,则所有其他项目将立即可见,因为它们实际上是相同的对象。

解决方案是将test的实例化移动到循环内部。

IList<Test> myList = new List<Test>();

foreach (DataRow dataRow in dataTable.Rows)
{
    Test test = new Test(); // Each loop iteration will now create a new instance of Test
    test.PatientID = Convert.ToInt64(dataRow.ItemArray[0]);
    test.LastName = dataRow.ItemArray[1].ToString();
    test.FirstName = dataRow.ItemArray[2].ToString();
    myList.Add(test);
}

如果您需要更好地了解这个问题,请查看.NET中的引用类型和值类型以及按引用/值传递。
.NET中的值类型和引用类型: http://msdn.microsoft.com/en-us/library/t63sy5hs.aspx
维基百科上有关指针的一些信息: http://en.wikipedia.org/wiki/Pointer_(computer_programming)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接