一尘不染

为什么向list <>添加新值会覆盖list <>中的先前值

c#

我实质上是想将多个项目添加到列表中,但最后所有项目的值都等于最后一个项目。

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

上面代码的两个项目与列表TagName设置为“栏”当我想到一个"Foo"和一个带"Bar"
为什么所有项目在结果列表中都具有相同的属性?

解释这一点的加分点,为什么更改public class Tagpublic struct Tag可使该代码按预期工作(不同的项目具有不同的值)。


如果那件事我的实际目标是创建派生的集合类,但是由于仅列出该问题就可能产生问题,因此仍然显示了我的目标。

通过一些教程,我成功地创建了一个收集类,该类继承了创建DataTable所需的功能,该DataTable可以作为表值参数传递给Sql
Server的存储过程。一切似乎都运行良好;我可以添加所有行,而且看起来很漂亮。但是,在仔细检查后,我注意到当我添加新行时,所有先前行的数据都会被新行的值覆盖。因此,如果我有一个字符串值为“
foo”的行,并添加了第二个值为“ bar”的行,则将插入第二行(制作一个包含两行的DataTable),但是这两行的值均为“ bar”
”。谁能知道为什么会这样吗?这是一些代码,

以下是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; }
}
}

这些称为:

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

阅读 834

收藏
2020-05-19

共1个答案

一尘不染

您在Tag循环内使用的是对象的相同实例,因此对的每次更新TagName都指向相同的引用。在循环内移动声明,以在循环的每个遍历上获取一个新鲜的对象:

foreach (string t in tagList)
{
    Tag _tag = new Tag(); // create new instance for every iteration

    _tag.tagName = t;
    tags.Add(_tag);
}

对于额外的部分-
当您Tag从复制操作更改classstruct复制操作(调用时发生)时,tags.Add(_tag)复制整个实例(本质上是创建一个新实例),与原始class情况不同,在原始情况下,仅将同一个实例的引用复制到调用的参数中,然后复制到列表的元素(有关如何传递给方法调用的说明,请参见C#按值传递与按引用struct传递)。

2020-05-19