* 정의

 

C#의 모든 타입은 object의 상속을 받고 있다. 기본 데이터 타입, 복합 데이터 타입 그리고 그 타입이 참조 타입이든 값 타입이든 예외 없이 모두 object이다. ildasm 툴로 확인하면 모두 object(System.Object)를 상속받고 있다는 것을 볼 수 있다. 간단히 계층 구조에서 루트이다. 심지어 값 타입을 나타내는 System.ValueType 조차 object를 상속받고 있다.

 

object는 C#의 모든 타입을 다룰 수 있으며 기본적인 기능과 리플렉션관련 기능을 제공한다.

 

< 간단한 계층 구조 다이어그램 >

 

< ildasm으로 봤을 때 System.Object를 상속받는다. >

 

< 값 타입을 나타내는 System.ValueType에서 object의 가상함수를 오버라이딩하고 있다. >

 

 

* 동작 방식

 

- object의 가상 함수

 

암시적으로 object를 상속 받고 있기 때문에 사용자에게 특정 기능을 구현 코드를 강요하지는 않지만 다음과 같은 가상 함수를 오버라이딩하여 사용할 수 있다.

 

다음과 같은 종류를 가지고 있다.

 

  • Equals : 객체간 비교를 지원하기 위해 오버라이딩한다.
  • GetHashCode : 객체를 구분하기 위한 객체에 해당하는 값(숫자)를 생성하기 위해 오버라이딩한다. 이를 기반으로 해시 테이블의 사용을 지원한다.
  • ToString : 클래스 인스턴스를 설명하는 문자열을 만들기 위해 오버라이딩한다.
  • Finalize : 객체를 가비지 컬렉터가 수거하기 전에 리소스나 정리 관련 코드를 실행하기 위해 오버라이딩한다.

 

위에서 3가지 함수의 시그니처는 다음과 같다. 필요에 따라 구현하면 된다.

  • public virtual bool Equals(Object? obj);
  • public virtual bool Equals(Object? obj);
  • public virtual string? ToString();

 

Finalize는 소멸자를 통해 선언할 수 있다. 자식 클래스 소멸자 > 부모 클래스의 소멸자 호출이 보장되도록 코드가 생성되기 때문에 C++처럼 가상 소멸자를 신경쓸 필요 없다.

 

 

- object 사용 시 주의 사항 : Boxing Unboxing

 

예를 들어 C#의 Collection과 같은 여러 타입에 대해 처리할 수 있는 컨테이너 형 클래스를 설계한다고 가정해보자.

 

모든 타입은 object 타입이므로 object를 내부 객체로 가지도록 만들 수 있다. 하지만 이렇게 설계하게 되면 박싱과 언박싱 과정이 발생하게 된다.

 

박싱 과정을 방지하기 위해 다음과 같은 방법을 고려해볼 수 있다.

  • object타입을 받는 일반적인 메소드를 만들고 특정 타입에 대한 오버로딩된 메소드를 만든다. 이렇게 오버로딩된 메소드들에서는 박싱 과정이 발생하지 않는다. 하지만 지원하지 않는 타입이 들어왔을 때 박싱 과정을 거치게 된다.
  • 제네릭(generic)을 사용하도록 디자인한다. CLR은 클래스 객체를 만들고 제니릭 타입 인수를 지정할 때 닫힌 제네릭 형식(closed generic type, 타입을 확정한다는 뜻인 것 같다.)을 만든다. 여기서 메소드는 타입 별로 존재하고 매개변수를 박싱하지 않고 호출될 수 있다.

 

 

 

'C#' 카테고리의 다른 글

[C#] var  (0) 2022.06.28
[C#] 박싱과 언박싱(Boxing and Unboxing)  (0) 2022.06.28
[C#] string vs StringBuilder  (0) 2022.06.28
[C#] Nullable 타입  (0) 2022.06.28
[C#] 값 타입과 참조 타입(Value type, Reference type)  (0) 2022.06.28

+ Recent posts