* 정의
- 박싱(Boxing)
박싱이란 값 타입을 object나 인터페이스 타입(해당 값 타입이 상속하고 있는 인터페이스)으로 변환하는 과정이다. CLR이 값 타입을 박싱할 때 값을 object(System.Object)에 래핑하여 힙에 저장된다.(원래 기본적으로 값 타입은 스택에 저장된다.)
- 언박싱(Unboxing)
언박싱이란 object로 부터 값 타입을 추출하는 과정이다.
박싱은 암묵적으로 이루어지고 언박싱은 명시적으로 수행된다. C#에서 박싱과 언박싱을 통해 어떤 값 타입이라도 object로 다룰 수 있게 된다.
* 동작 방식
- 박싱과 언박싱이 발생하는 시점
예를 들어 값 타입 int i 와 object o 사이의 박싱 언박싱 과정은 다음과 같은 코드에서 나타난다.
i 가 박싱되고 o에 할당되는 과정이다.
int i = 3;
// 박싱
object o = i;
o가 언박싱되고 i에 할당되는 과정이다.
object o = 3;
// 언박싱
i = (int)o;
박싱과 언박싱은 둘 다 비싼 연산이다. 박싱 연산은 힙에 할당하는 작업도 포함되어 있기 때문에 더 비싸다. 내부 동작 원리를 확인해보면 이유를 알 수 있다.
- 박싱의 원리
박싱은 값 타입을 가비지 컬렉터가 관리하는 힙에 할당하기 위해 사용되며, 값 타입에서 object, 인터페이스 타입(값 타입이 상속 받고 있는 인터페이스)으로의 암묵적 변환을 의미한다. 값 타입을 박싱하는 것은 object 인스턴스를 힙에 할당하고 값을 새로운 object에 복사하는 작업이다. 새롭게 힙에 할당하기 때문에 박싱된 값 타입(힙)과 값 타입 원본(스택)은 독립된 메모리 공간에 위치한다.

ildasm을 통해서 보면 OpCode가 box인 것을 확인할 수 있다.

- 언박싱의 원리
언박싱은 object나 인터페이스 타입에서 값 타입으로의 명시적 변환을 의미한다. 언박싱 연산은 다음과 같이 구성된다.
- object 인스턴스를 검사하여 변환할 값 타입으로 object에 박싱되었는지 확인한다.
- 인스턴스에서 값 타입 변수로 값을 복사한다.

ildasm을 통해서 보면 OpCode가 unbox인 것을 확인할 수 있다.

런타임에서 문제 없이 값 타입 언박싱이 수행되려면 언박싱할 값 타입이 이전에 해당 값 타입을 박싱하여 생성된 객체(에 대한 참조)가 언박싱 되어야 한다.
null을 언박싱하면 NullReferenceException, 호환불가능한 값으로 언박싱하면 InvalidCastException이 발생한다.
int i = 3;
object o = i; // 박싱
//short s = (short)o; // 언박싱과정에서 InvalidCastException 발생
object? o2 = null;
int i2 = (int)o2; // 언박싱과정에서 NullReferenceExceptino 발생
// 사실 (int) 으로 캐스팅을 시도하는 시점에서 컴파일러가 경고 메시지를 출력한다.
* 박싱 언박싱 유무 성능 비교
object 타입을 요소로 가지고 있는 Collection의 ArrayList와 여러 타입 인수를 통해 요소의 타입을 결정할 수 있는 Generic Collection의 List를 간단히 성능 비교해보았다.
ildasm을 통해서 보았을 때 box, unbox 명령어가 Collection 버전에서만 나타났다.

'C#' 카테고리의 다른 글
| [C#] 강력한 형식 언어(Strongly Typed Language) (0) | 2022.06.28 |
|---|---|
| [C#] var (0) | 2022.06.28 |
| [C#] object (0) | 2022.06.28 |
| [C#] string vs StringBuilder (0) | 2022.06.28 |
| [C#] Nullable 타입 (0) | 2022.06.28 |