[C#] 얕은 복사, 깊은 복사

natae·2022년 8월 21일
0

Csharp

목록 보기
3/9

개요

  • 얕은 복사는 .NET에서 제공하는 MemberWiseClone()와 대입의 차이 확인
  • 깊은 복사는 직렬화 라이브러리 활용

코드

// .NET 6
// See https://aka.ms/new-console-template for more information
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;

var city1 = new City();

// ShallowCopy with Substitution
city1.Init();

var city2 = city1;
city2.Name = "Busan";
city2.Budget = 90;
city2.CityInfo.CityId = 2;

city1.Print();
city2.Print();

// ShallowCopy with MemberwiseClone
city1.Init();

var city3 = city1.ShallowCopyWithMemberwiseClone();
city3.Name = "Jeju";
city3.Budget = 75;
city3.CityInfo.CityId = 3;

city1.Print();
city3.Print();

// DeepCopy with Bson Serialization
city1.Init();

var city4 = city1.DeepCopyWithBson();
city4.Name = "Anyang";
city4.Budget = 60;
city4.CityInfo.CityId = 4;

city1.Print();
city4.Print();

public class City
{
    public string Name;
    public int Budget;
    public CityInfo CityInfo;

    public void Init()
    {
        Name = "Seoul";
        Budget = 100;
        CityInfo = new CityInfo
        {
            CityId = 1,
        };
    }

    public City ShallowCopyWithMemberwiseClone()
    {
        return (City)MemberwiseClone();
    }

    public City DeepCopyWithBson()
    {
        var serializer = new JsonSerializer();

        var memoryStreamForWrite = new MemoryStream();
        using (var writer = new BsonDataWriter(memoryStreamForWrite))
        {
            serializer.Serialize(writer, this);
        }

        var memoryStreamForRead = new MemoryStream(memoryStreamForWrite.ToArray());
        using (var reader = new BsonDataReader(memoryStreamForRead))
        {
            return serializer.Deserialize<City>(reader);
        }
    }
    public void Print()
    {
        Console.WriteLine($"Name: {Name}");
        Console.WriteLine($"Budget: {Budget}");
        Console.WriteLine($"CityInfo.CityId: {CityInfo.CityId}");
        Console.WriteLine("---------------------------------");
    }
}
public class CityInfo
{
    public int CityId;
}

출력

Name: Busan
Budget: 90
CityInfo.CityId: 2
---------------------------------
Name: Busan
Budget: 90
CityInfo.CityId: 2
---------------------------------
Name: Seoul
Budget: 100
CityInfo.CityId: 3
---------------------------------
Name: Jeju
Budget: 75
CityInfo.CityId: 3
---------------------------------
Name: Seoul
Budget: 100
CityInfo.CityId: 1
---------------------------------
Name: Anyang
Budget: 60
CityInfo.CityId: 4
---------------------------------

결론

  • 대입의 경우 기존 객체를 동일하게 가르키는 포인터를 생성함
    • 모든 수정사항이 동일하게 반영됨
  • MemberWiseClone()의 경우 참조 타입이 아니면 복사하고, 참조 타입이면 동일하게 가르키는 포인터를 생성함 (string은 예외)
    • 수정사항이 int, string 타입만 독립적으로 반영됨
  • 깊은 복사에 bson을 사용한 이유는 다른 직렬화는 추가 작업이 필요해서
    • messagepack은 클래스에 프로퍼티 설정 작업 필요
    • protobuf는 프로토 파일 및 컴파일 작업 필요
  • 깊은 복사에는 BinaryFormatter를 이용한 직렬화 방법도 있는데 보안상 이유로 더이상 지원하지 않음

참고 문헌

profile
서버 프로그래머

0개의 댓글