C#에서 클래스는 태생적으로 참조 형식이다.
스택영역에 있는 참조가 힙영역에 할당된 객체의 메모리를 가리킨다.
SampleClass a = new SampleClass(); SampleClass b = a;
와 같은 코드에서는 a와 b는 서로 같은 객체를 가리키고 있다.같이 a의 필드를 변경하면 b의 필드도 변경된다. 이를 얕은 복사(Shallow Copy)라 한다.
반면, a 인스턴스를 힙영역에 새로운 객체를 할당하여 복사하는 것은 깊은 복사(Deep Copy)이다.
간단한 복사
using System;
class TestDeepCopy
{
public int field1;
public int field2;
public TestDeepCopy DeepCopy()
{
TestDeepCopy copy = new TestDeepCopy();
copy.field1 = this.field1;
copy.field2 = this.field2;
return copy;
}
public void Print()
{
Console.WriteLine("{0} {1}", field1, field2);
}
}
테스트
class MainApp
{
static void Main(string[] args)
{
Console.WriteLine("Shallow Copy");
{
TestDeepCopy source = new TestDeepCopy();
source.field1 = 10;
source.field2 = 20;
TestDeepCopy target = source;
target.field2 = 30;
source.Print();
target.Print();
}
Console.WriteLine("Deep Copy");
{
TestDeepCopy source = new TestDeepCopy();
source.field1 = 10;
source.field2 = 20;
TestDeepCopy target = source.DeepCopy();
target.field2 = 30;
source.Print();
target.Print();
}
}
}
결과
Shallow Copy
10 30
10 30
Deep Copy
10 20
10 30
ICloneable 인터페이스를 활용한 깊은 복사
class TestDeepCopy : ICloneable
{
public int field1;
public int field2;
public object Clone()
{
TestDeepCopy copy = new TestDeepCopy();
copy.field1 = this.field1;
copy.field2 = this.field2;
return copy;
}
public void Print()
{
Console.WriteLine("{0} {1}", field1, field2);
}
}
.Net 프레임워크에는 ICloneable이라는 인터페이스가 있다.
깊은 복사 기능을 위한 Clone() 메소드 하나 만을 갖고 있음.
호환성을 위해 깊은 복사를 하려면 ICloneable 인터페이스를 사용하는 게 좋다.
TestDeepCopy target = source.Clone as TestDeepCopy
참조형 변수를 필드로 갖는 클래스의 복사
C#에서 클래스는 참조형이라고 얘기했었다.
예컨대, A라는 클래스에서 B 클래스를 필드로 갖는다고 하자.
class Field
{
public int value;
public Field(int value)
{
this.value = value;
}
public override string ToString()
{
return value.ToString();
}
}
class Test
{
public int field1;
public Field field2;
public void Print()
{
Console.WriteLine("{0} {1}", field1, field2);
}
}
이런 경우에는 Clone 메소드에서
Test copy = new Teest(); copy.field2 = this.field2
와 같은 방식으로는 깊은 복사가 되지 않는다.깊은 복사를 하려면
copy.field2 = new Field(this.field2.value);
처럼 새 인스턴스를 만들어 줘야한다.
Clone 메소드 구현
class Test : ICloneable
{
public int field1;
public Field field2;
public object ShallowCopy()
{
//MemberwiseClone()은 System.Object의 메소드로 Shallow Copy를 만들어준다.
return this.MemberwiseClone();
}
public object Clone()
{
Test copy = this.MemberwiseClone() as Test;
copy.field2 = new Field(this.field2.value);
return copy;
}
public void Print()
{
Console.WriteLine("{0} {1}", field1, field2);
}
}
테스트
class MainApp
{
static void Main(string[] args)
{
Console.WriteLine("Shallow Copy");
{
Test source = new Test();
source.field1 = 10;
source.field2 = new Field(20);
Test target = source.ShallowCopy() as Test;
target.field2.value = 30;
source.Print();
target.Print();
}
Console.WriteLine("Deep Copy");
{
Test source = new Test();
source.field1 = 10;
source.field2 = new Field(20);
Test target = source.Clone() as Test;
target.field2.value = 30;
source.Print();
target.Print();
}
}
}
참조
뇌를 자극하는 C# 5.0 프로그래밍, 박상현, 한빛미디어
'아카이빙 > C#' 카테고리의 다른 글
[C#] 형변환과 is, as (0) | 2018.06.18 |
---|---|
[C#] this() 생성자 (0) | 2018.06.18 |
[C#] static 필드와 메소드 (0) | 2018.06.18 |
[C#] 유니티에서 foreach 성능은 개선되었을까 (1) | 2017.05.06 |
[C#] FieldInfo와 PropertyInfo (0) | 2017.05.06 |