2014-01-29 30 views
3

我有一个有趣的问题。我有一类人:添加到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; } 
    } 

我创建一个观察的集合:

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

我加5项像这样的集合:

test.myFillTest(new Person { Name = "None" }, 5); 

如果我更改了一个实例名称:

test[2].Name = "John"; 

所有在收集变化的项目,因为如果他们都指向同一件事。 这将是什么原因?顺便说一下,这适用于类型为int的字符串和字符串,但不适用于typeof类。

+0

要添加相同的参考(值2)。添加值类型时,它可以工作,因为它们不是引用。 –

+1

正如使用nbr作为参数名称一样令人困惑。你应该写你的变量名,这样如果你阅读你的代码(或其他人),他们将很容易知道是什么。更好的办法是使用“int numberofcopies”,然后你的代码立即更具可读性。 value1和value2也不是很具描述性。 – TylerD87

回答

4

这是因为Person类是引用类型,而整数是值类型。当你添加5次相同的int时,它被复制,当你添加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 
} 
+0

谢谢你给出了一个很好的答案,我一直在思考这些问题,而且这个工作很棒! –

2

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

2

它很简单 - 要添加value2到集合nbr倍。或者更确切地说,当添加一个对象时(如同您在示例中),您正在向同一对象nbr次添加参考。所以,如果你改变它,你可以改变它们。

0

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

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); 
相关问题