繁体   English   中英

添加到Observable Collection时的奇怪行为

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM