首页 > 解决方案 > 在 foreach 循环中将项目添加到 ObservableCollection 会影响上级列表中的整个项目?

问题描述

我会尽量简短。

我有一个名为Error. 此类包含一个名为的属性Suggestions,它是一个ObservableCollection<string>.

在一种方法中,我创建了一个用 LINQ 语句Error命名的 s列表,AllInstances然后foreach在该列表上执行循环。在循环内部,我将一项添加到对象的Suggestions集合中Error

问题在于,在循环的每一轮中,该项目都会添加到AllInstances. 因此,如果循环有 3 个回合,那么每个成员AllInstances都会添加 3 个项目!

正常行为应该是每个Suggestions集合都添加了 1 个项目,而不是 3 个。

这是代码:

错误类

public class Error : INotifyPropertyChanged, ICloneable
    {
        public ObservableCollection<string> Suggestions { get; set; }
    }

方法的代码

List<Error> AllInstances = (from paragraph in DocRef.LatestState
                            from error in paragraph.Errors
                            where error.Word == sourceError.Word
                            select error).ToList();

foreach (Error _er in AllInstances)
    {
        _er.Suggestions.Add(newSuggestion);
    }

// At this point, if "AllInstances.Count" was 3, every "_er.Suggestions" in "AllInstances"
// will also have 3 items in it!

这对我来说似乎很不合逻辑,以至于我高度怀疑这是我已经做过的事情,或者是我还不知道的类型结构的基本知识。

我很感激任何帮助。谢谢你。

标签: c#foreachobservablecollection

解决方案


好的,正如我在上一次对该问题的评论中提到的那样,我研究了Error在一些需要它的情况下克隆类的方式。原来我在方法中克隆了这样的对象:

public object Clone ()
        {
            return new Error
            {
                ...
                Suggestions = Suggestions,
                ...
            };
        }

我注意到Errorclass 的所有其他属性都是默认类型(不可变?),例如string, intand bool,唯一不同的是 Suggestions 类型的集合ObservableCollection<string>。我想可能是因为其他属性都表现正确并且没有导致引用同一实例的问题,这个集合在设计上与其他集合不同,需要手动重新实例化。所以我做了:

public object Clone ()
        {
            return new Error
            {
                ...
                Suggestions = new ObservableCollection<string>(Suggestions),
                ...
            };
        }

我只是在方法中重新创建了属性,Clone解决了在 foreach 循环中引用同一实例的问题。

我希望对代码有更深入了解的人可以启发我和其他可能偶然发现这个问题的人,关于这个问题的逻辑以及那些不可变类型和ObservableCollection.


推荐阅读