20200218[C#] Object형식, 박싱 언박싱
Object형식
Object형식은 모든 형식의 궁극적인 기반 클래스이다. 그 어떤 형식도 Object로 상향 캐스팅할 수 있다. 범용적으로 쓰이는 Stack구조를 살펴보자
class Stack
{
public int Position;
object[] array = new object[10];
public void Push(object o)
{
array[Position++] = o;
}
public object Pop()
{
return array[Position--];
}
}
static void Main(string[] args)
{
Stack stack = new Stack();
stack.Push("Apple");
string answer = (string)stack.Pop(); //하향 캐스팅
}
그 어떤 형식의 인스턴스라도 push와 pop이 가능하다. 하지만 Object형식이기 때문에 Pop을 할 때는 명시적 캐스팅이 필요하다. 또, object는 하나의 클래스이며, 따라서 참조 형식이다. 그렇긴 하지만 int 같은 값 형식과 object사이의 캐스팅도 가능하다. c#의 이러한 특징을 형식 통합이라고 부른다.
Object(참조) 형식도 int(값) 형식으로 변환이 가능하다.
박싱과 언박싱
위에서 살짝 언급한 내용으로 값 형식 인스턴스를 참조 형식 인스턴스로 변환하는 것을 박싱이다. 그럼 그 반대는? 언박싱이겠지라고 생각하는데 맞기는 하는데 한 가지 조건이 있다. 바로, 박싱 과정을 거친 객체를 되돌리는 것이 언박싱이다.
간단한 예제로 살펴보자
1.박싱
int x = 10;
object obj = x; //int 박싱
1.언박싱
int x = 10;
object obj = x; //int 박싱
int y = (int)obj; //int 언박싱
박싱은 그냥 하면 되고, 언박싱은 명시적 캐스팅이 필요하다. 이렇게 쉽게 참조 타입과 값 타입 사이에서 형식 변환을 쉽게 할 수 있다는 것은 매우 편리하다. 모든 함수와 자료구조 타입을 objct형식으로 만들어놓으면 캐스팅만 잘 사용한다면 코드 중복 없이 짧고 쉽게 설계가 가능할 것 같아 보인다. (이 세상에서 분명 공짜는 없다. 박싱과 언박싱에서는 단점이 있다. 다음에 설명 )
하지만, 기억해야 할 것은 objct는 참조 형식이고, int는 값 형식이다.
박싱과 언박싱의 복사 의미론
박싱(값 -> 참조)은 값 형식 인스턴스를 새 객체로 복사하고, 언박싱(참조 -> 값)은 객체의 내용을 다시 값 형식 인스턴스로 복사한다. 말로 풀었을 때 무슨 소리인지 모르겠다. 이 과정은 어떤 과정인지 한 가지 예를 보고 살펴보자.
int i = 5;
object boxed = i;
i = 3;
Console.WriteLine(boxed);
Console.WriteLine(i);
Console.WriteLine(boxed);
먼저 출력 결과를 먼저 알려주면 위에서부터 5,3,5이다. 답을 맞혔다면 저 말을 이해가 된 것이다. boxed와 i는 서로 다른 인스턴스 즉, "i는 boxed라는 새로운 인스턴스를 만들고 자신의 값을 복사했다."라는 말이다. 그래서 i의 값을 바꿔도 boxed의 값은 변경되지 않는다.