2012-11-19 18 views
33

Na przykładC# jak przypisać listę <T> bez odniesienia?

List<string> name_list1 = new List<string>(); 
List<string> name_list2 = new List<string>(); 

później w kodzie:

name_list1.Add("McDonald"); 
name_list1.Add("Harveys"); 
name_list1.Add("Wendys"); 

name_list2 = name_list1; // I make a copy of namelist1 to namelist2 

Więc z tego punktu chciałbym zachować dodanie elementu lub dokonywania zmian w name_list2 bez wpływu name_list1. Jak mogę to zrobić?

Odpowiedz

81
name_list2 = new List<string>(name_list1); 

To będzie klonować listę.

+1

+1 - elokwentny, lubię go, gdy 'operator new' jest używany w ten sposób. –

+0

To jest ładne, czyste rozwiązanie. Po prostu dodam dla wyjaśnienia, że ​​jeśli to zrobisz, nie powinieneś zawracać sobie głowy inicjowaniem name_list2 z 'nowym Listem ()' konstruktorem kilka linii powyżej, ponieważ będziesz tworzył obiekt tylko po to, by go wyrzucić. Nie jest to wielka sprawa, ale zły nawyk kodowania. – adv12

+16

to nadal odwołuje się do name_list1 – DoIt

7
name_list2 = new List<string>(name_list1); // Clone list into a different object 

W tym momencie obie listy są różne obiekty. Możesz dodać elementy do listy2 bez wpływu list1

+1

"Możesz dodawać elementy do listy2 bez wpływania na listę1", jest to błędne. – thinco

+0

To nie działa dla mnie. Ciągle się odnosił. Użyłem tego zamiast http://stackoverflow.com/a/25035202/1367450 –

+0

można dodawać i usuwać z listy 2 bez wpływu na listę1, ale po zaktualizowaniu elementu będzie propagować na obu listach –

4

Problemem jest przypisanie. Do przypisania name_list2 = name_list1;, masz dwa różne obiekty List na stercie wskazane przez zmienne name_list1 i name_list2. Wypełniasz name_list1, co jest w porządku. Ale przypisanie mówi, „make name_list2 punkt do tego samego obiektu na stercie jako name_list1”. Lista, do której kiedyś wskazywał name_list2, nie jest już dostępna i zostanie zebrana. Co naprawdę chcesz to skopiować zawartość z name_list1 do name_list2. Możesz to zrobić pod numerem List.AddRange. Zauważ, że spowoduje to "płytką" kopię, która jest w porządku dla przykładu, który cytujesz, gdzie zawartość listy są łańcuchami, ale może nie być tym, co chcesz, gdy członkowie listy są bardziej złożonymi obiektami. Wszystko zależy od twoich potrzeb.

+0

Ta odpowiedź wyjaśnia, co dzieje się nieco bardziej niż inne, które dotychczas czytałem, ale zgadzam się, że rozwiązanie 'name_list2 = new List (name_list1);' zaproponowane przez innych jest prawdopodobnie czystszym sposobem na wykonanie kopii. – adv12

3

Another opcje to: Głęboka Klonowanie

public static T DeepCopy<T>(T item) 
     { 
      BinaryFormatter formatter = new BinaryFormatter(); 
      MemoryStream stream = new MemoryStream(); 
      formatter.Serialize(stream, item); 
      stream.Seek(0, SeekOrigin.Begin); 
      T result = (T)formatter.Deserialize(stream); 
      stream.Close(); 
      return result; 
     } 

tak,

można użyć:

name_list2 = DeepCopy<List<string>>(name_list1); 

czyli

name_list2 = DeepCopy(name_list1); 

będzie również działać.

+2

Ładne rozwiązanie, ale pamiętaj, że zawsze musisz mieć atrybut "Serializable" na swojej klasie, jeśli jest to "typ referencyjny". –

+0

Tak ... Masz rację. Jest to najważniejsza kwestia, o której należy pamiętać w przypadku głębokiego klonowania. – ayc

1

Poniżej przedstawiono alternatywne rozwiązanie:

List<string> name_list1 = new List<string>(); 
    List<string> name_list2 = new List<string>(); 

    name_list1.Add("McDonald"); 
    name_list1.Add("Harveys"); 
    name_list1.Add("Wendys"); 

    name_list2.AddRange(name_list1.ToArray()); 

ToArray() Metoda egzemplarze słowem 'name_list1' do nowej tablicy, które następnie dodać do name_list2 metodą AddRange().

1

Lubię LINQ dla tego ...

Jeśli elementy listy są prymitywy lub struktury potem ...

L2 = L1.ToList() 

Jeśli elementy listy są klasy potem ...

L2 = L1.Select(x => x.Copy()).ToList(); 

Gdzie Copy może być po prostu płytką ekspozycją z MemberWiseClone, lub może być jakąś implementacją głębokiej kopii.

Powiązane problemy