【问题标题】:Generic method to create deep copy of all elements in a collection创建集合中所有元素的深层副本的通用方法
【发布时间】:2010-04-30 13:21:40
【问题描述】:

我有各种不同对象类型的 ObservableCollections。我想编写一个方法,该方法将采用任何这些对象类型的集合并返回一个新集合,其中每个元素都是给定集合中元素的深层副本。这是特定类的示例

   private static ObservableCollection<PropertyValueRow> DeepCopy(ObservableCollection<PropertyValueRow> list)
   {
        ObservableCollection<PropertyValueRow> newList = new ObservableCollection<PropertyValueRow>();
        foreach (PropertyValueRow rec in list)
        {
            newList.Add((PropertyValueRow)rec.Clone());
        }
        return newList;
   }

我怎样才能使这个方法对任何实现 ICloneable 的类都通用?

【问题讨论】:

  • 作为一个公平的警告,并非所有 ICloneable 实现实际上都是深拷贝。

标签: c# generics


【解决方案1】:

你可以这样做:

private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list)
    where T : ICloneable
{
   ObservableCollection<T> newList = new ObservableCollection<T>();
   foreach (T rec in list)
   {
       newList.Add((T)rec.Clone());
   }
   return newList;
}

请注意,您可以通过使用 IEnumerable&lt;T&gt; 来使其更通用,而 LINQ 使这更容易:

private static ObservableCollection<T> DeepCopy<T>(IEnumerable<T> list)
    where T : ICloneable
{
   return new ObservableCollection<T>(list.Select(x => x.Clone()).Cast<T>());
}

【讨论】:

  • 我试过了,但它似乎不认为这是一种通用方法。我收到“非泛型声明上不允许使用约束”编译器错误。
  • 糟糕——我打错了;您只需要在方法名称的末尾加上&lt;T&gt;
  • 阅读完所有这些 Chuck Norris 式的关于 Jon Skeet 的笑话后,我发现这很难相信 - Jon Skeet 在他的帖子中有一个错字。但确实是一篇漂亮的帖子。感谢您提供整洁的第二个基于 LINQ 的版本。整洁的。非常整洁。
  • 该死!此代码在 windows phone 7 项目中不起作用。说icloneable不可访问!任何可用的 Skeet 的解决方法?
  • @Bragboy:你收藏的价值是什么?你总是可以用同样的方法引入你自己的界面......
【解决方案2】:
private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list) 
    where T : ICloneable 
{ 
   ObservableCollection<T> newList = new ObservableCollection<T>(); 
   foreach (T rec in list) 
   { 
       newList.Add((T)rec.Clone()); 
   } 
   return newList; 
} 

【讨论】:

  • 这似乎是 Jon Skeet 帖子的“克隆”版本 :-)
  • 当他在 14:15 纠正它时,你认为我如何“克隆”了一个在 13:26 剪断为正确版本的代码……我没有时间机器。跨度>
【解决方案3】:

我使用了一个非常相似的函数,它适用于所有可以构造的 ICollections(例如许多标准集合):

    public static TContainer CloneDeep<TContainer, T>( TContainer r ) 
        where T : ICloneable
        where TContainer: ICollection<T>, new()
    {
        // could use linq here, but this is my original pedestrian code ;-)
        TContainer l = new TContainer();
        foreach(var t in r)
        {
            l.Add( (T)t.Clone() );  
        }

        return l;
    }

不幸的是,编译器无法推断出类型,因此必须显式传递它们。对于不止少数几个电话,我写了一个专业。这是 Lists 的一个例子(它本身可以用隐式推导的 T 来调用)。

    public static List<T> CloneListDeep<T>( List<T> r ) where T : ICloneable
    {
        return CloneDeep<List<T>, T>( r );
    }

我广泛使用此功能来创建列表副本,作为可以取消的对话框上数据网格视图的数据源。当对话框被取消时,修改后的列表被简单地丢弃;当对话框被确定时,编辑的列表只是替换原来的。当然,这种模式的先决条件是要有一个语义正确且维护良好的T.clone()

【讨论】:

    猜你喜欢
    • 2016-06-21
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    相关资源
    最近更新 更多