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