Kopiowanie obiektów List<T> -> List<t>

0

Pytanie pewnie o podstawy podstaw, jednak wolę się upewnić co do poprawności mojego myślenia.

Pracuję (spokojnie, tylko hobbystycznie) z listami obiektów, które same w sobie mogą (ale nie muszą) zawierać kolejne listy obiektów składowych.
Przykładowo mam listę obiektów klasy [zestaw], z których każdy zawiera jeszcze listę obiektów [kredki].

Mam przygotowane dane wejściowe, jednak chcę część danych odfiltrować aby wyświetlić tylko cześć danych, tworzę więc kopię lokalną.
Jak już wiem polecenie List<T> new_list = old_list prowadzi do kłopotów*, bo dane są przekazywane przez referencję.

Pytanie: jak skopiować poprawnie nową listę tak, aby była niezależną kopią listy wejściowej?

Normalnie użyłbym prostej pętli:

        private List<T> Copy_List(List<T> old_list)
        {
            new_list = new List<T>();

            foreach (var i in old_list)
            { new_list.Add(i); }

            return new_list;
        }

ALE...
ale zaniepokoiło mnie to, co wyczytałem w głębi internetu:

Gdy wywołujemy clone dla klasy zawierającej obiekty innych klas (agregaty), należy pamiętać by w metodzie __clone() wywołać polecenie clone dla obiektów zawieranych, w innym wypadku kopia będzie posiadać referencję do obiektów zawieranych w oryginale.

Co prawda nie używam Clone, ale mam wątpliwości: czy zaproponowna pętla foreach jest poprawnym rozwiązaniem dla agregatów?

  • z drugiej strony dziwne, że
    int a = 10;
    int b = a;
    b = 0;
    to a = 10, w końcu int to też obiekt.
0

Najpierw zacznij od zupełnych podstaw, skoro dziwisz się że a = 10, weź jakąś książke, później rozwiązuj problem deep copy. Jak wstawisz List za int to też tak samo zadziała.

Kopiowanie rzadko w ogóle jest potrzebne, najlepiej żyć w świecie immutable i się tym nie przejmować.

A metoda do klonowania jest oczywiście zła, co prawda lista jest już nowym obiektem, ale wszystko w środku niej już nie, musiałby robić nie Add(i) ale Add(Copy(i)) i tak rekurencyjne wgłąb (co jest definicja deep copy).

0

swoją drogą żeby skopiować listę wystarczy

new List<T>(old_list);

albo nawet:

old_list.ToList();
0

@obscurity: No tak średnio bym powiedzial. Jak zmienisz wartość jakiejs property elementu listy nr1, to w nowej liscie tez bedziesz mial te zmianę.

edit:
Kaczka dobrze podpowiada, jak kiedys potrzebowalem głębokiego kopiowania to korzystałem z tego kodu:

public static class ExtensionMethods
{
    // Deep clone
    public static T DeepClone<T>(this T a)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, a);
            stream.Position = 0;
            return (T) formatter.Deserialize(stream);
        }
    }
}

Warunek jest taki ze twoja klasa musi być z atrybutem Serializable

0

@obscurity: nic nie kopiujesz. Tworzysz nową listę z tymi samymi obiektami. Piszesz głupoty.

0

@Antar: Do samego wyswietlenia to nie ma sie czym martwic. Filtrujesz jedna liste (A, B , c, d) i dostajesz listę (A, b) więc wyświetlacz tylko A, B. W drugiej liście A i B to te same obiekty co w pierwszej ale nie ma to znaczenia dla samego wyświetlenia danych.

1 użytkowników online, w tym zalogowanych: 0, gości: 1