8

I have various ObservableCollections of different object types. I'd like to write a single method that will take a collection of any of these object types and return a new collection where each element is a deep copy of elements in the given collection. Here is an example for a specifc class

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

How can I make this method generic for any class which implements ICloneable?

bwarner
  • 872
  • 1
  • 5
  • 12

3 Answers3

25

You could do something like this:

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

Note that you could make this more general by taking IEnumerable<T>, and LINQ makes it even easier:

private static ObservableCollection<T> DeepCopy<T>(IEnumerable<T> list)
    where T : ICloneable
{
   return new ObservableCollection<T>(list.Select(x => x.Clone()).Cast<T>());
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I had tried that, but it doesn't seem to consider that a generic method. I get a "Constraints are not allowed on non-generic declarations" compiler error. – bwarner Apr 30 '10 at 13:44
  • 1
    Oops - I had a typo; you just need `` at the end of the method name. – Jon Skeet Apr 30 '10 at 14:15
  • 1
    having read all these Chuck Norris-type jokes about Jon Skeet, I find this very hard to believe - that Jon Skeet had a typo in his post. But a beautiful post indeed. Thanks for the neat second LINQ-based version. Neat. Very neat. – Peter Perháč Nov 01 '10 at 11:02
  • dang! this code does not work in a windows phone 7 project. says icloneable is not accessible ! Any work around available Skeet ? – bragboy Jul 25 '12 at 10:01
  • @Bragboy: Well what are the values in your collection? You could always introduce your own interface with the same method... – Jon Skeet Jul 25 '12 at 11:04
  • @JonSkeet: Yes, i ended up doing something similar. Thank you for this neat method, i have some other places (non WP7) which require this. – bragboy Jul 25 '12 at 13:13
3
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; 
} 
Hinek
  • 9,519
  • 12
  • 52
  • 74
0

I use a very similar function which works with all ICollections which can be constructed (e.g. many standard collections):

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

Unfortunately the compiler isn't able to deduce the types so that one must pass them explicitly. For more than a handful calls I write a specialization. Here is an example for Lists (which itself can be called with implicitly deduced T).

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

I use this function extensively in order to create copies of lists serving as datasources for datagridviews on dialogs which can be canceled. The modified list is simply discarded when the dialog is cancelled; when the dialog is OKed the edited list simply replaces the original. Prerequisite for this pattern is, of course, to have a semantically correct and well maintained T.clone().

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62