W Visual Basic często konieczne jest stworzenie kopii obiektu, aby zmieniać dane w nowy sposób, nie naruszając pierwotnej struktury. Pojawia się zadanie rozróżnienia kopiowania płytkiego (shallow) i głębokiego (deep), szczególnie jeśli obiekty zawierają zagnieżdżone typy referencyjne.
Historia zagadnienia:
Kopiowanie płytkie kopiuje tylko wartości prymitywnych właściwości i odwołania do zagnieżdżonych obiektów, podczas gdy kopiowanie głębokie tworzy nowe instancje wszystkich zagnieżdżonych obiektów. Różnice są zasadnicze przy pracy ze skomplikowanymi danymi, na przykład, gdy obiekt zawiera kolekcje lub inne obiekty.
Problem:
Jeśli skopiować obiekt przez odwołanie lub użyć standardowej metody MemberwiseClone, zmiana zagnieżdżonych obiektów wpłynie na pierwotną strukturę wraz z kopią — jest to niebezpieczne dla logiki biznesowej i może prowadzić do trudnych do wyśledzenia błędów.
Rozwiązanie:
W VB.NET nie ma gotowego sposobu na głębokie kopiowanie, dlatego należy go zaimplementować ręcznie lub przez serializację. Zazwyczaj implementuje się metodę użytkownika DeepCopy, tworząc nowe instancje wszystkich zagnieżdżonych obiektów.
Przykład kodu kopiowania płytkiego i głębokiego:
Class Person Public Name As String Public Address As Address ' Kopiowanie płytkie Public Function ShallowCopy() As Person Return CType(Me.MemberwiseClone(), Person) End Function ' Kopiowanie głębokie Public Function DeepCopy() As Person Dim copy As Person = CType(Me.MemberwiseClone(), Person) copy.Address = New Address() With {.City = Me.Address.City} Return copy End Function End Class Class Address Public City As String End Class
Kluczowe cechy:
Co zwróci operator = przy kopiowaniu obiektu klasy w Visual Basic?
Odpowiedź: Operator = dla typów referencyjnych przypisuje odwołanie, a nie kopiuje wartości. Dlatego obie zmienne będą wskazywać na ten sam obiekt.
Dim a As New Person() Dim b As Person = a ' Teraz a i b — odwołania do tego samego obiektu
Czy można użyć MemberwiseClone do głębokiego kopiowania?
Odpowiedź: Nie. Metoda MemberwiseClone realizuje tylko kopiowanie płytkie — wszystkie zagnieżdżone typy referencyjne są kopiowane przez odwołanie.
Dlaczego serializacja nie jest zawsze uniwersalnym sposobem na głębokie kopiowanie?
Odpowiedź: Serializacja działa tylko z obiektami serializowalnymi i może nie wspierać właściwości typu Object lub nieoznaczonych jako Serializable. Poza tym, serializacja działa wolniej niż standardowe kopiowanie.
Klient kopiuję obiekt zamówienia operatorem = do złożenia nowego zamówienia, nie podejrzewając, że zagnieżdżona lista pozycji pozostała ta sama dla dwóch obiektów.
Zalety: Szybko, prosto
Wady: Zmiany w jednym zamówieniu zmieniają również drugie — krytyczne błędy w ewidencji towarów.
Zaimplementowano metodę DeepCopy do kopiowania zamówienia wraz z wszystkimi zagnieżdżonymi towarami i adresem dostawy.
Zalety: Niezawodne oddzielenie danych, poprawna logika biznesowa
Wady: Należy uważnie śledzić strukturę obiektu, więcej kodu do utrzymania