개요
- 얕은 복사는 .NET에서 제공하는 MemberWiseClone()와 대입의 차이 확인
- 깊은 복사는 직렬화 라이브러리 활용
코드
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
var city1 = new City();
city1.Init();
var city2 = city1;
city2.Name = "Busan";
city2.Budget = 90;
city2.CityInfo.CityId = 2;
city1.Print();
city2.Print();
city1.Init();
var city3 = city1.ShallowCopyWithMemberwiseClone();
city3.Name = "Jeju";
city3.Budget = 75;
city3.CityInfo.CityId = 3;
city1.Print();
city3.Print();
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를 이용한 직렬화 방법도 있는데 보안상 이유로 더이상 지원하지 않음
참고 문헌