【问题标题】:Modify new collection without touching the original one修改新收藏而不触及原始收藏
【发布时间】:2013-03-07 15:37:22
【问题描述】:

我的目标是在不触及原始收藏的项目的情况下获得一份收藏副本,其中删除了指定的项目。我有以下课程:

public class Foo
{
    public string Name { get; set; }
}

而我正在做的操作是:

 var collection = new Collection<Foo>
                         {
                             new Foo {Name = "Name1"},
                             new Foo {Name = "Name2"},
                             new Foo {Name = "Name3"},
                             new Foo {Name = "Name4"}
                         };
    var newCollection = new Collection<Foo>(collection);

    Foo f = collection.FirstOrDefault(x => x.Name == "Name2");
    if (f != null)
    {
        newCollection.Remove(f);
    }

即我正在从“newCollection”中删除该项目,但问题在于以下行:

newCollection.Remove(f);

也从原始集合中删除该项目,即从“集合”对象中。我只想修改“newCollection”而不是“collection”。我怎样才能做到这一点?下面这行不是在做深拷贝吗:

 var newCollection = new Collection<Foo>(collection);

如果是,那为什么原来的对象会受到影响?

我知道我也可以通过这条线路实现我的目标:

var newCollection = collection.Where(x => x.Name != "Name2");

但我对上面发生的删除内容和深拷贝内容感到两难。

【问题讨论】:

  • 是 System.Collections.ObjectModel.Collection

标签: c# generics collections deep-copy


【解决方案1】:

这是因为Collection&lt;T&gt;(IList&lt;T&gt;) constructor 的行为:

列表的元素不会被复制。列表由集合包装,因此列表元素的后续更改通过集合可见。

如果你想要一个集合的浅拷贝1,你可以改用List&lt;T&gt;

List<Foo> newCollection = new List<T>(collection);

(看到Collection&lt;T&gt; 被这样使用有点奇怪。它通常用作其他泛型集合的 base 类。)


1 这是一个浅拷贝,因为它只是复制每个元素的值作为引用,而不是克隆每个Foo 对象。如果你写:

newCollection[0].Name = "Hello!";
Console.WriteLine(collection[0]);

...它仍然会打印“Hello!”。围绕现有集合创建包装器根本不是真正创建副本,浅深。

【讨论】:

  • 你的意思是通过这个“new List(collection);”进行深拷贝,对吧?而不是我认为是您回复中的错字的浅拷贝。
  • @RockySingh:不,我的意思是浅拷贝。深拷贝会克隆每个元素。浅拷贝只是复制 references - 但仍会创建一个独立的集合。我已经编辑了答案以提供脚注。
【解决方案2】:

你需要克隆它,newCollection 只是对原始集合的引用。

【讨论】:

  • 这一行怎么样,然后 "var newCollection = new Collection(collection);"
  • @RockySingh:查看我的答案 - 以及文档。
  • 看我的回答,看我的回答!乔恩,你为什么这么受关注****?
【解决方案3】:

Collection&lt;Foo&gt;(collection) 仅包装提供的集合,因此对集合的任何更改也会影响原始集合。

您应该使用List&lt;Foo&gt; 来做您想做的事,因为List&lt;T&gt;(IEnumerable&lt;T&gt;) 的构造函数会复制原始集合中的值。

var collection = new Collection<Foo>
                         {
                             new Foo {Name = "Name1"},
                             new Foo {Name = "Name2"},
                             new Foo {Name = "Name3"},
                             new Foo {Name = "Name4"}
                         };
    var newCollection = new List<Foo>(collection);

    Foo f = collection.FirstOrDefault(x => x.Name == "Name2");
    if (f != null)
    {
        newCollection.Remove(f);
    }

【讨论】:

    【解决方案4】:

    您可以尝试这样做。

      var newCollection = new Collection<Foo>();
    
    collection.ToList().ForEach(x => newCollection.Add(x));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-12
      • 1970-01-01
      • 2013-05-23
      • 2013-08-02
      • 2014-05-11
      • 2019-12-17
      • 2015-06-20
      相关资源
      最近更新 更多