C# 添加到可观察集合时的奇怪行为
我有一个有趣的问题。我有一个班上的人:C# 添加到可观察集合时的奇怪行为,c#,.net,observablecollection,C#,.net,Observablecollection,我有一个有趣的问题。我有一个班上的人: 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;
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; }
}
我创建了一个可观察的集合:
ObservableCollection<Person> test = new ObservableCollection<Person>();
public static void myFillTest<T>(this ObservableCollection<T> value1, T value2, int nbr)
{
for (int x = 0; x < nbr; x++)
{
value1.Add(value2);
}
}
如果我在一个实例中更改名称:
test[2].Name = "John";
集合中的所有项都会更改,就好像它们都指向同一个对象一样。
为什么会这样?顺便说一句,这适用于int类型的T和string,但不适用于typeof类。newperson{Name=“None”}仅在调用方法时实例化一次。所以它们都引用同一个对象。这是因为类Person是引用类型,而integer是值类型。当您将同一个int添加5次时,它被复制;当您将person添加5次时,它的一个实例被添加到5个不同的索引中。您可以在此处阅读有关引用类型的信息。如果希望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
}
public static void MyFillTest(此可观察采集值1,T值2,int-nbr)
{
对于(int x=0;x
这很简单-您正在将value2
添加到集合nbr
中。或者更确切地说,当添加一个对象时(如您在示例中所示),您正在添加对同一对象的引用nbr
次。因此,如果您更改一个对象,那么您将更改所有对象。Person对象实例化一次,其引用被使用5次。您可以通过使用memberwise克隆来创建原始对象的浅层副本来克服此问题。此扩展方法将完成您尝试执行的操作:
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);
}
}
您正在添加相同的引用(值2)。当添加ValueType时,它之所以有效是因为它们不是引用。您应该编写变量名,这样,如果您仔细阅读了代码(或其他人阅读了代码),他们就可以很容易地知道是什么。更好的方法是使用“int numberofcopies”,这样您的代码就会立即变得更可读。value1和value2也不是很具有描述性。谢谢你给出了一个很好的答案,我一直在按照这些思路思考,这非常有效!
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);