2010-04-30 16 views
8

Tengo varios ObservableCollections de diferentes tipos de objetos. Me gustaría escribir un único método que tome una colección de cualquiera de estos tipos de objetos y devolver una nueva colección donde cada elemento sea una copia profunda de los elementos en la colección dada. Este es un ejemplo de una clase specifcMétodo genérico para crear una copia en profundidad de todos los elementos en una colección

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

¿Cómo puedo hacer que este método genérico para cualquier clase que implementa ICloneable?

+4

Como advertencia, no todas las implementaciones de ICloneable son en realidad copias en profundidad. –

Respuesta

24

Se podría hacer algo como esto:

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

Tenga en cuenta que usted podría hacer esto más en general, tomando IEnumerable<T>, y LINQ hace que sea aún más fácil:

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

Lo había intentado, pero no parece considerarlo como un método genérico. Obtengo el error de compilación "No se permiten las restricciones en declaraciones no genéricas". – bwarner

+1

Vaya, tuve un error tipográfico; solo necesita '' al final del nombre del método. –

+1

habiendo leído todas estas bromas de Chuck Norris sobre Jon Skeet, encuentro esto muy difícil de creer, que Jon Skeet tuvo un error tipográfico en su publicación. Pero una hermosa publicación de hecho. Gracias por la prolija segunda versión basada en LINQ. Ordenado. Muy aseado. –

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

esta parece ser una versión "clonada" de la publicación de Jon Skeet :-) –

+8

¿Cómo crees que he "clonado" un código recortado en la versión correcta a las 13:26 cuando lo corrigió a las 14:15 ... no lo hago No tengo una máquina del tiempo. – Hinek

+0

+1 para la máquina del tiempo :) – WiiMaxx

0

Puedo utilizar una función muy similar que funciona con todos los ICollections que se pueden construir (por ejemplo, muchas colecciones estándar):

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

Desafortunadamente, el compilador no puede deducir los tipos, por lo que uno debe pasarlos explícitamente. Durante más de un puñado de llamadas escribo una especialización. Aquí hay un ejemplo de Listas (que a su vez se puede llamar con T deducido implícitamente).

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

utilizo esta función ampliamente con el fin de crear copias de las listas que sirven como fuentes de datos para datagridviews en los cuadros de diálogo que pueden ser canceladas. La lista modificada simplemente se descarta cuando se cancela el diálogo; cuando el diálogo está OK, la lista editada simplemente reemplaza el original. Requisito previo para este patrón es, por supuesto, tener un T.clone() semánticamente correcto y bien mantenido.

Cuestiones relacionadas