添加到Observable Collection时的奇怪行为

时间:2014-01-29 13:51:28

标签: 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; 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和字符串,但不适用于类型类。

5 个答案:

答案 0 :(得分:4)

这是因为类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
}

答案 1 :(得分:2)

当您调用方法时,新人{Name =“None”}仅实例化一次。所以他们都引用同一个对象。

答案 2 :(得分:2)

这很简单 - 您要将value2添加到集合nbr次。或者更确切地说,在添加对象时(就像在您的示例中一样),您将引用添加到同一对象nbr次。因此,如果您更改一个,则将其全部更改。

答案 3 :(得分:1)

此扩展方法将执行您要执行的操作:

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

答案 4 :(得分:0)

Person对象被实例化一次,其引用被使用了5次。您可以通过使用成员克隆来创建原始对象的浅副本来克服这个问题。