[英]Odd behavior when adding to an Observable Collection
我有一个有趣的问题。 我有一个班级人员:
public class Person
{
public string Name { get; set; }
public int? Score { get; set; }
public int NbrOfWins { get; set; }
public int NbrOfLosses { get; set; }
public int HighScore { get; set; }
}
我创建了一个Observable集合:
ObservableCollection<Person> test = new ObservableCollection<Person>();
我有一个扩展方法添加到observable集合:
public static void myFillTest<T>(this ObservableCollection<T> value1, T value2, int nbr)
{
for (int x = 0; x < nbr; x++)
{
value1.Add(value2);
}
}
我将5个项目添加到集合中,如下所示:
test.myFillTest(new Person { Name = "None" }, 5);
如果我在一个实例中更改名称:
test[2].Name = "John";
集合中的所有项目都会发生变化,就像它们都指向同一个东西一样。 这会是什么原因? 顺便说一句,这适用于int类型的T和字符串,但不适用于typeof类。
这是因为类Person是引用类型,而整数是值类型。 当你添加相同的int 5次时,它被复制,当你添加5次时,它的一个实例被添加到5个不同的索引。 您可以在http://msdn.microsoft.com/en-us/library/490f96s2.aspx上阅读有关参考类型的信息。 如果希望它按预期工作,则需要复制person类型的对象。
您可以将代码更改为以下内容,以便始终创建新对象:
public static void MyFillTest<T>(this ObservableCollection<T> value1, T value2, int nbr)
{
for (int x = 0; x < nbr; x++)
{
if (typeof(T).IsValueType)
{
value1.Add(value2);
}
else
{
if (value2 is ICloneable)
{
ICloneable cloneable = (ICloneable)value2;
value1.Add((T)cloneable.Clone());
}
}
}
}
public class Person : ICloneable
{
public string Name { get; set; }
public int? Score { get; set; }
public int NbrOfWins { get; set; }
public int NbrOfLosses { get; set; }
public int HighScore { get; set; }
#region ICloneable Members
public object Clone()
{
return new Person
{
Name = this.Name,
Score = this.Score,
NbrOfWins = this.NbrOfWins,
NbrOfLosses = this.NbrOfLosses,
HighScore = this.HighScore
};
}
#endregion
}
当您调用方法时,新人{Name =“None”}仅实例化一次。 所以他们都引用了同一个对象。
这很简单 - 你正在为nbr
次集合添加value2
。 或者更确切地说,在添加对象时(就像在您的示例中一样),您将添加对同一对象的引用 nbr
次。 因此,如果您更改一个,则将其全部更改。
此扩展方法将执行您要执行的操作:
public static void myFillTest<T>(this ObservableCollection<T> value1, Action<T> init, int nbr) where T: new()
{
for (int x = 0; x < nbr; x++)
{
var value2 = new T();
init(value2);
value1.Add(value2);
}
}
像这样称呼它:
test.myFillTest(p => p.Name = "None", 5);
Person对象实例化一次,其引用使用5次。 您可以通过使用成员克隆来创建原始对象的浅副本来克服这个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.