Chciałbym wykonać kopię listy w swoim programie jednak nie chce to działać.
Mam w programie dwie listy, łączę je, następnie wykonuje operacje na nowej połączonej liście. Jednak nie chcę wprowadzać modyfikacji w tych dwóch listach składowych.
Kiedy próbuję zrobić tak
List Merged = new List();
Merged.AddRange(List1);
Merged.AddRange(List2);
Jednak wykonując operacje na liście Merged zmieniam również listy LIst1 i List2. Próbowałem też tak:
List CopyList1 = new List(List1);
List CopyList2 = new List(List2);
List Merged = new List();
Merged.AddRange(CopyList1);
Merged.AddRange(CopyList2);
Jednak to na nic bo zmieniając coś w Merged modyfikują się też CopyList oraz List. W jaki sposób prawidłowo wykonać kopię listy? Myślałem o zwykłej funkcji w swojej klasie która utworzy nową listę a następnie ustawi odpowiednie wartości na polach tej klasy. Jednak to wydaje mi się zbyt czasochłonne robić kolejne pętle.
Nie wiem, czy już sobie poradziłeś. Jeśli nie, to: Tworzenie obiektów klonowalnych (ICloneable) (strona 287) Jak już zaimplementujesz ten interfejs w swojej klasie, to możesz dodać do kodu taką metodę rozszerzającą:
static class ListExtensions
{
public static IList Clone(this IList listToClone) where T: ICloneable
{
return listToClone.Select(item => (T)item.Clone()).ToList();
}
}
Oczywiście mam zamiar się z tym zapoznać. Nic nie robiłem póki co ale zanim się z tym zapoznam pewnie przerobię funkcję tak aby zapisywało do dwóch list na raz.
List1 i List2 są wypełniane w zależności od pewnej zmiennej. Dla uproszczenia załóżmy że jest to zmienna bool i jeśli true to dopisujemy do List1 a jeśli false to do List2. Na początek po prostu dodam w pętli dodam żeby zawsze też wpisywało w Merged.
Najprostszym chyba sposobem klonowania obiektów jest serializacja, nie trzeba się wówczas bawić w pętle i ręczne kopiowanie wszystkich właściwości:
public class UniversalCloner
{
public static T DeepClone(T obj)
{
object objResult = null;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = bf.Deserialize(ms);
}
return (T)objResult;
}
}
Serializacja to nie za bardzo służy do klonowania obiektów (przynajmniej w javie). Przychylam się do rozwiązania matzu. Nie wiem jak w c# w javie każdy obiekt ma metodę clone(), która jest deklarowana w object, trzeba ją przedefiniować we własnym obiekcie i zaimplementować jak ma byc klonowany: głeboko, płytko…
Tzn. się to rozwiązanie, które zaproponował somekind da się połączyć z tym co ja zaproponowałem. To akurat nie stanowi problemu. Problem jaki tutaj widzę to przede wszystkim wydajność, a przynajmniej tak mi się wydaje. Sądzę, że rozwiązanie oparte o serializację będzie o wiele wolniejsze.
Swoją drogą przed chwilą zauważyłem inny problem z tym rozwiązaniem. Co jeśli jakieś pole zostanie oznaczone jako NonSerialized? Spowoduje to, że wartość tego pola nie zostanie przypisana w utworzonej kopii.
kostek135 , kod, który wkleiłem można przecież użyć w metodzie Clone. To, że serializacja niekoniecznie do tego służy - no cóż, to od programisty zależy, jakiego mechanizmu do czego używa.
matzu , podałem przykład najkrótszego w implementacji rozwiązania. Jeśli ktoś potrzebuje większej wydajności albo kontroli nad tym procesem, to niestety musi napisać ręcznie.
Ten pierwszy rozdział z książki (Filozofia platformy .NET) to jeden z trudniejszych. Później jest kilka bardziej przyjemnych. Ja Ci podałem numer strony, gdzie masz wyjaśnione o co chodzi z tym kopiowaniem (to jest tylko 4-5 stron, IMO w miarę przystępnie napisanych). Te 2 linki co wrzuciłem też są całkiem dobre (traktuj je jako rozszerzenie tych kilku stron). Na podstawie tych trzech źródeł coś na pewno naskrobiesz (później możesz tu wrzucić do przejrzenia/poprawy(?)).
Ten kod co podałeś na początku nie działa dlatego, że Ty w tych listach przechowujesz instancje typów referencyjnych. Gdy tworzyłeś te nowe listy w oparciu o elementy już istniejących list, to przekazywałeś do nich referencje, które wskazują na obiekty w pamięci, a nie kopie tych obiektów. Miałeś więc kilka list, które przechowywały te same referencje, a więc wskazywały na dokładnie te same obiekty w pamięci.
Gdyby te listy przechowywały typy wartościowe, np. int-y, string-i (string to taki specyficzny typ wartościowy; w rzeczywistości jest to typ referencyjny, który sprawia wrażenie jakby był wartościowy - w książce chyba też jest gdzieś o tym mowa), to ten kod działałby poprawnie. Gdy przekazujesz do metody typ wartościowy, to zawsze przekazujesz jego kopię.