我实际上是在尝试将多个项目添加到列表中,但最后所有项目都具有与最后一项相同的值.
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);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码生成两个项目的列表,TagName当我期望一个"Foo"和一个时,设置为"Bar" "Bar".为什么所有项目在结果列表中具有相同的属性?
解释为什么更改public class Tag以public struct Tag使此代码按预期工作(不同的项具有不同的值)的加分点.
如果重要的是我的实际目标是创建派生集合类,但由于问题只发生在列表中,它可能是可选的,仍然显示我的目标在下面.
按照一些教程,我可以成功创建一个集合类,它继承了创建DataTable所需的功能,可以将其作为表值参数传递给Sql Server的存储过程.一切似乎都运作良好; 我可以添加所有行,它看起来很漂亮.但是,经过仔细检查,我注意到当我添加一个新行时,所有前一行的数据都会被新行的值覆盖.因此,如果我有一个字符串值为"foo"的行,并且我添加了第二行,其值为"bar",则将插入第二行(使用两行的DataTable),但这两行的值都为"bar" ".任何人都可以看到为什么会这样?下面是一些代码,它们可以工作但是有点简化(Tag类已经减少了以便于解释).
以下是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; }
}
}
Run Code Online (Sandbox Code Playgroud)
这些被称为如下:
//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);
}
Run Code Online (Sandbox Code Playgroud)
Ahm*_*eed 38
您在Tag循环内使用相同的对象实例,因此每次更新TagName都是相同的引用.在循环内移动声明以在循环的每次传递中获取新对象:
foreach (string t in tagList)
{
Tag _tag = new Tag(); // create new instance for every iteration
_tag.tagName = t;
tags.Add(_tag);
}
Run Code Online (Sandbox Code Playgroud)
对于奖金的一部分-当您更改Tag从class到struct复制操作(当你调用发生这种情况tags.Add(_tag))拷贝整个实例(本质上是创建新的)不像在原来的class情况下,当只对同一个实例的引用将被复制到调用和参数,然后到列表的元素(有关如何传递给方法调用的说明,请参阅C#按值传递而不是按引用struct传递).