namespace TestCSharp
{
class MyClass
{
public int fieldValue1;
public int fieldValue2;
}
public class Program
{
static void Main(string[] args)
{
MyClass source = new MyClass();
source.fieldValue1 = 10;
source.fieldValue2 = 20;
MyClass target = source;
target.fieldValue2 = 30;
Console.WriteLine($"{source.fieldValue1}, {source.fieldValue2}");
Console.WriteLine($"{target.fieldValue1}, {target.fieldValue2}");
}
}
}
값은 어떻게 나올까??
1.번
10, 20
10, 30
10, 30
10, 30
답은 2번이다.
일단 source라는 객체의 메모리를 보자면은
스택 | 힙 |
---|---|
다른 데이터 | 다른 데이터 |
다른 데이터 | 다른 데이터 |
source | fieldValue1, fieldValue2 |
target | (source가 가르키는 곳을 똑같이 가르킨다) |
다른 데이터 | 다른 데이터 |
지금 이런식이다.
우리는 지금
MyClass target = source;
이렇게 해주었을 때
target만의 새로운 힙 메모리에 공간을 할당하여 값만 source 로부터 복사해서
target이 새로운 힙메모리의 주소를 가르크게 하고싶다면,
를 해야한다.
그런데 c#에서는 이런 "깊은 복사"를 자동으로 해주는 구문이 없다.
그래서 자체적으로 깊은 복사를 하는 코드를 구현해야한다.
class MyClass
{
public int fieldValue1;
public int fieldValue2;
public MyClass DeepCopy()
{
MyClass newCopy = new MyClass();
newCopy.fieldValue1 = this.fieldValue1;
newCopy.fieldValue2 = this.fieldValue2;
return newCopy;
}
}
이런식으로 MyClass를 return 하는 생성자를 반환하는 함수를 만들어 주어야한다.
static void Main(string[] args)
{
MyClass source = new MyClass();
source.fieldValue1 = 10;
source.fieldValue2 = 20;
MyClass target = source.DeepCopy();
target.fieldValue2 = 30;
Console.WriteLine($"{source.fieldValue1}, {source.fieldValue2}");
Console.WriteLine($"{target.fieldValue1}, {target.fieldValue2}");
}
이렇게해주면 이제 서로 다른 힙메모리를 가지는 객체를 만든 것이고
아까 원한
10, 20
10, 30
이라는 값이 출력되는 것을 확인이 가능하다.
System 네임스페이스에 ICloneable이라는 인터페이스가 구현되어있다.
"인터페이스란"?
클래스가 구현해야하는 메소드 목록 이다.
이 인터페이스는 "깊은 복사"기능을 가질 클래스가 있을 경우
해당 클래스는 ICloneable 을 상속하는 것이 좋다.
class MyClass : ICloneable
{
public int fieldValue1;
public int fieldValue2;
public object Clone()
{
MyClass newCopy = new MyClass();
newCopy.fieldValue1 = fieldValue1;
newCopy.fieldValue2 = fieldValue2;
return newCopy;
}
}
지금 책에서는 반환 타입이 MyClass인데
그러면 컴파일 에러 뜸
반환 형식이 object형식이어야하는데
https://truecode.tistory.com/47 object관련 블로그
object형식은 "상속" 덕분에 어떤 데이터든지 다룰수 있는 데이터 형식이다
int, float, char, string, bool 와 같은 값형식들의 "부모"이다.
object는 "박상", "언박싱"을 통해 힙에 데이터를 올리고
객체가 힙메모리의 주소를 가르키는 형식이다.
int a = 123;
object b = (object)a; // a에 담긴 값을 박싱하여 힙에 저장
int c = (int)b; // b에 담긴 값은 언박싱하여 스택에 저장
이런식인 것이다.
반환형식이 object라 힙에 올라가기 때문에 또한 어떤 데이터든지 다룰 수 있기 때문에
(클래스도 복합 데이터 형식이라 힙에 올라간다)
Class 라는 데이터 형식도 담을 수 있기 때문에 ㄱㅊ다는 것이다.
(그런데 MyClass 반환은 왜 안될까...??)