C# 为什么向 list<> 添加新值会覆盖 list<> 中以前的值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2156482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does adding a new value to list<> overwrite previous values in the list<>
提问by Tim C
I'm essentially trying to add multiple items to a list but at the end all items have the same value equal to last item.
我本质上是在尝试将多个项目添加到列表中,但最后所有项目的值都与最后一个项目相同。
public class Tag
{
public string TagName { get; set; }
}
List<Tag> tags = new List<Tag>();
Tag _tag = new Tag();
string[] tagList = new[]{"Foo", "Bar"};
foreach (string t in tagList)
{
_tag.tagName = t; // set all properties
//Add class to collection, this is where all previously added rows are overwritten
tags.Add(_tag);
}
The code above produces list of two items with TagName
set to "Bar" when I expect one for "Foo"
and one with "Bar"
. Why all items have the same properties in the resulting list?
TagName
当我期望一个 for"Foo"
和一个 with时,上面的代码会生成两个设置为“Bar”的项目列表"Bar"
。为什么所有项目在结果列表中都具有相同的属性?
Bonus point for explanation why changing public class Tag
to public struct Tag
makes this code work as expected (different items have different values).
解释为什么更改public class Tag
为public struct Tag
使此代码按预期工作的奖励点(不同的项目具有不同的值)。
If that matter my actual goal is to create derived collection class, but since issue happens with just list it likely optional, still showing what my goal is below.
如果那件事我的实际目标是创建派生集合类,但由于问题发生在仅列出它可能是可选的,仍然显示我的目标在下面。
Following a few tutorials and such I was able to successfully create a collection class which inherits the functionality needed to create a DataTable which can be passed to a Sql Server's stored procedure as a table value parameter. Everything seems to be working well; I can get all of the rows added and it looks beautiful. However, upon closer inspection I notice that when I add a new row, the data for all of the previous rows is overwritten with the value for the new row. So if I have a row with a string value of "foo" and I add a second row with the value "bar", the second row will be inserted (making a DataTable with two rows) but both rows will have the value "bar". Can anyone see why this would be? Here is some of the code, which works but has been a bit simplified (the Tag class has been reduced for ease of explanation).
按照一些教程等,我能够成功创建一个集合类,该类继承了创建 DataTable 所需的功能,该 DataTable 可以作为表值参数传递给 Sql Server 的存储过程。一切似乎都运行良好;我可以添加所有行,它看起来很漂亮。但是,经过仔细检查,我注意到当我添加一个新行时,之前所有行的数据都被新行的值覆盖。因此,如果我有一个字符串值为“foo”的行,并且我添加了值为“bar”的第二行,则将插入第二行(制作具有两行的 DataTable),但两行的值都将为“bar” ”。谁能看出为什么会这样?这是一些代码,
The following is the Collection class's:
以下是 Collection 类的:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using Microsoft.SqlServer.Server;
namespace TagTableBuilder
{
public class TagCollection : List<Tag>, IEnumerable<SqlDataRecord>
{
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
var sdr = new SqlDataRecord(
new SqlMetaData("Tag", SqlDbType.NVarChar)
);
foreach (Tag t in this)
{
sdr.SetSqlString(0, t.tagName);
yield return sdr;
}
}
}
public class Tag
{
public string tagName { get; set; }
}
}
These are called as follows:
它们被称为如下:
//Create instance of collection
TagCollection tags = new TagCollection();
//Create instance of object
Tag _tag = new Tag();
foreach (string t in tagList)
{
//Add value to class propety
_tag.tagName = t;
//Add class to collection, this is where all previously added rows are overwritten
tags.Add(_tag);
}
采纳答案by Ahmad Mageed
You're using the same instance of the Tag
object inside the loop, so each update to the TagName
is to the same reference. Move the declaration inside the loop to get a fresh object on each pass of the loop:
您在Tag
循环内使用对象的相同实例,因此对 的每次更新TagName
都指向相同的引用。移动循环内的声明以在每次循环时获得一个新对象:
foreach (string t in tagList)
{
Tag _tag = new Tag(); // create new instance for every iteration
_tag.tagName = t;
tags.Add(_tag);
}
For bonus part - when you change Tag
from class
to struct
copy operation (that happens when you call tags.Add(_tag)
) copies whole instance (essentially creating new one) unlike in original class
case when only reference to the same single instance is copied into the parameter of the call and then to the list's element (see C# pass by value vs. pass by referencefor explanation on how struct
passed to method calls).
对于奖金的一部分-当您更改Tag
从class
到struct
复制操作(当你调用发生这种情况tags.Add(_tag)
)拷贝整个实例(本质上是创建新的)不像在原来的class
情况下,当只对同一个实例的引用将被复制到调用的参数,然后列表的元素(有关如何传递给方法调用的解释,请参阅C# 按值传递与按引用struct
传递)。
回答by Aaron
In the loop where you add the tags to the collection, you're using the same object instance of Tag. Essentially, you're setting a Tag's name to the first value in tagList and adding it to the collection, then you're changing that same Tag's name to the second value in tagList and adding it again to the collection.
在将标签添加到集合的循环中,您使用的是相同的 Tag 对象实例。本质上,您将标签的名称设置为 tagList 中的第一个值并将其添加到集合中,然后将相同的标签名称更改为 tagList 中的第二个值并再次将其添加到集合中。
Your collection of Tags contains several references to the same Tag object! Instantiate _tag inside the for loop each time before setting the Tag's name and adding it to the collection.
您的标签集合包含对同一个标签对象的多个引用!每次在设置标签名称并将其添加到集合之前,在 for 循环中实例化 _tag。