Visual Basic에서는 원본 구조체를 변경하지 않고 새로운 방식으로 데이터를 수정하기 위해 객체의 복사본을 만드는 경우가 많습니다. 따라서 얕은 복사(shallow)와 깊은 복사(deep)를 구분하는 것이 필요하며, 특히 객체가 중첩된 참조형 타입을 포함하는 경우에 중요합니다.
질문의 배경:
얕은 복사는 원시 속성의 값과 중첩 객체에 대한 참조만 복사하고, 깊은 복사는 모든 중첩 객체의 새로운 인스턴스를 생성합니다. 이는 특히 복잡한 데이터를 다룰 때, 예를 들어 객체가 컬렉션이나 다른 객체를 포함할 경우 기본적인 차이점이 됩니다.
문제:
객체를 참조로 복사하거나 MemberwiseClone 표준 메서드를 사용하면, 중첩 객체가 변경될 때 원본 구조체도 복사본과 함께 변경됩니다. 이는 비즈니스 로직에 위험을 초래하고, 찾기 어려운 버그를 야기할 수 있습니다.
해결책:
VB.NET에는 직접적인 깊은 복사 방식이 없으므로 수동으로 구현하거나 직렬화를 통해 수행해야 합니다. 일반적으로 사용자 정의 DeepCopy 메서드를 구현하여 모든 중첩 객체의 새로운 인스턴스를 생성합니다.
얕은 복사 및 깊은 복사의 코드 예:
Class Person Public Name As String Public Address As Address ' 얕은 복사 Public Function ShallowCopy() As Person Return CType(Me.MemberwiseClone(), Person) End Function ' 깊은 복사 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
주요 특징:
Visual Basic에서 클래스 객체를 복사할 때 = 연산자가 반환하는 값은 무엇인가요?
답변: 참조형 타입에 대한 = 연산자는 값을 복사하는 것이 아니라 참조를 할당합니다. 따라서 두 변수는 동일한 객체를 가리킵니다.
Dim a As New Person() Dim b As Person = a ' 이제 a와 b는 동일한 객체를 참조합니다.
MemberwiseClone을 깊은 복사에 사용할 수 있나요?
답변: 아닙니다. MemberwiseClone 메서드는 오직 얕은 복사만 구현하므로 모든 중첩 참조형 타입은 참조로 복사됩니다.
왜 직렬화가 항상 깊은 복사의 범용적인 방법이 아닌가요?
답변: 직렬화는 직렬화 가능한 객체에만 작동하며, Object 타입 또는 Serializable로 표시되지 않은 속성을 지원하지 않을 수 있습니다. 또한, 직렬화는 표준 복사보다 느리게 작동합니다.
고객이 새로운 주문을 작성하기 위해 = 연산자로 주문 객체를 복사하는데, 중첩 리스트의 항목이 두 객체에 걸쳐 남아있다는 사실을 모릅니다.
장점: 빠르고 간단함
단점: 하나의 주문에서의 변경이 다른 주문에도 영향을 미치게 되어 상품 회계에 심각한 오류를 초래함.
모든 중첩 상품과 배송 주소를 함께 복사하기 위한 DeepCopy 메서드가 구현되었습니다.
장점: 데이터의 신뢰성 있는 분리, 올바른 비즈니스 로직
단점: 객체 구조를 주의 깊게 살펴봐야 하며, 지원을 위한 코드량이 증가함.