2010-04-30 12 views
8

Mam różne ObservableCollections różnych typów obiektów. Chciałbym napisać jedną metodę, która pobierze kolekcję dowolnego z tych typów obiektów i zwróci nową kolekcję, w której każdy element jest głęboką kopią elementów z danej kolekcji. Oto przykład dla SZCZEGÓLNE klasyOgólna metoda tworzenia głębokiej kopii wszystkich elementów w kolekcji

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

Jak mogę uczynić to metoda rodzajowa dla każdej klasy, która implementuje ICloneable?

+4

Jako uczciwe ostrzeżenie, nie wszystkie możliwe do wdrożenia implementacje są w rzeczywistości kopiami pełnymi. –

Odpowiedz

24

Można zrobić coś takiego:

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

pamiętać, że można zrobić to bardziej ogólnie biorąc IEnumerable<T> i LINQ czyni go jeszcze łatwiej:

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

Próbowałem tego, ale nie wydaje mi się, że to rodzajowa metoda. Otrzymuję "Ograniczenia są niedozwolone dla nie generycznych deklaracji" błąd kompilatora. – bwarner

+1

Ups - miałem literówkę; po prostu potrzebujesz '' na końcu nazwy metody. –

+1

po przeczytaniu wszystkich tych żartów z rodzaju Chucka Norrisa na temat Jona Skeeta, uważam, że trudno w to uwierzyć - że Jon Skeet miał literówkę w swoim poście. Ale rzeczywiście piękny post. Dzięki za schludną, drugą wersję opartą na LINQ. Schludny. Bardzo schludny. –

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

to wydaje się być "sklonowana" wersja postu Jona Skeeta :-) –

+8

Jak myślisz, jak "sklonowałem" kod wycięty w poprawnej wersji o 13:26, kiedy poprawił go o 14:15 ... nie mają wehikułu czasu. – Hinek

+0

+1 za maszynę czasu :) – WiiMaxx

0

używam bardzo podobna funkcja, która działa ze wszystkimi kolekcjami ICollections, które można skonstruować (np. wiele standardowych kolekcji):

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

Niestety kompilator nie jest w stanie wywnioskować typów, więc należy je jawnie przekazać. Po więcej niż kilku telefonach piszę specjalizację. Oto przykład Lists (który sam może zostać wywołany z domyślnie wydedukowanym T).

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

używam tej funkcji obszernie w celu tworzenia kopii list służących jako źródła danych dla datagridviews na dialogach, które mogą być anulowane. Zmodyfikowana lista jest po prostu odrzucana, gdy okno dialogowe jest anulowane; kiedy okno dialogowe jest OK, edytowana lista po prostu zastępuje oryginał. Warunkiem wstępnym dla tego wzorca jest oczywiście semantycznie poprawne i dobrze utrzymane T.clone().

Powiązane problemy