[vb.net] class에 대한 clone의 구현

class는 레퍼런스 타입인데 여기에 ICloneable의 Clone메서드를 구현하여 class의 내부값들을 그대로 복제할 수 있는 기능을 구현한다. 레퍼런스 타입은 하나의 메모리를 가리키고 있으므로 특정 인스턴스 값을 변경하면 다른 인스턴스의 값도 변경된다. 이를 극복하기 위하여 Clone 을 사용한다.

MemberwiseClone 메소드는 모든 value 타입 필드의 값을 그대로 복제하고 참조 타입인 경우는 참조로서 복제한다. 따라서 클래스 내부에 참조 타입 필드는 새로 생성하여 값을 옮겨 넣는 과정이 필요하다(shopping 클래스의 clone메서드와 order클래스의 clone메서드의 차이)

-- order.vb --
Imports System
Imports System.Text
Imports System.Collections.Generic

Public Class Order
    Implements ICloneable

    Public OrderNumber As String
    Public PONumber As String
    Public ShippingAddress As String

    Public Sub New(ByVal _OrderNumber As String, ByVal _PONumber As String, ByVal _ShippingAddress As String)
        OrderNumber = _OrderNumber
        PONumber = _PONumber
        ShippingAddress = _ShippingAddress
    End Sub

    ' create a clone
    Public Function Clone() As Object Implements System.ICloneable.Clone
        Return Me.MemberwiseClone
    End Function

    Public Overrides Function ToString() As String
        Return String.Format("Order Number is {0}, and PO number is {1}", OrderNumber, PONumber)
    End Function
End Class

-- shopping.vb --
Imports System
Imports System.Text
Imports System.Collections.Generic

Public Class Shopping
    Implements ICloneable

    Public Orders As New List(Of Order)

    Public Sub New()

    End Sub

    Public Overrides Function ToString() As String
        Dim str As New StringBuilder
        For Each e As Order In Orders
            str.AppendLine(String.Format("order{0}", e.OrderNumber))
        Next
        Return str.ToString
    End Function

    Public Function Clone() As Object Implements System.ICloneable.Clone
        Dim newShopping As New Shopping

        For Each e As Order In Me.Orders
            newShopping.Orders.Add(DirectCast(e.Clone, Order))
        Next

        Return newShopping
    End Function
End Class


--  module 1 --
Module Module1

    Sub Main()
        Dim originalShopping As New Shopping
        originalShopping.Orders.Add(New Order("0001", "P001", "address1"))
        originalShopping.Orders.Add(New Order("0002", "P002", "address2"))
        originalShopping.Orders.Add(New Order("0003", "P003", "address3"))

        Dim clonedShopping As Shopping = DirectCast(originalShopping.Clone, Shopping)

        originalShopping.Orders(0).OrderNumber = "0005"
        originalShopping.Orders(0).PONumber = "P005"
        originalShopping.Orders(0).ShippingAddress = "address5"

        Console.WriteLine(originalShopping.ToString)
        Console.WriteLine(clonedShopping.ToString)
        Console.ReadLine()
    End Sub

End Module