타입간 캐스팅
코딩을 하다보면 타입간 캐스팅을 해야하는 상황이 빈번하게 발생한다. 캐스팅은 일반적으로
Up Casting, Down Casting기능으로 쓰인다.
Up casting
- 파생된 객체가 베이스 클래스로 변환하는 캐스팅
Down casting
- 베이스 클래스에서 파생 클래스로 캐스팅
//System.Object에서 파생 된 base
public class base
{
}
//base에서 파생 된 derived
public class derived : base
{
}
class Program
{
static void Main(string[] args)
{
object ob = new derived(); //upcasting
Console.WriteLine(ob.GetType().ToString());
//derived 출력
Base b = (Base)ob; //downcasting
Console.WriteLine(b.GetType().ToString());
//derived 출력
derived d = (derived)b; //downcasting
Console.WriteLine(d.GetType().ToString());
//derived 출력
}
}
위의 코드는 캐스팅의 예시 이다. CLR기준으로 순서대로 설명을 해보자면
1. Main 함수 시작 후 CLR은 derived 인스턴스를 생성하여 인스턴스 포인터를 반환한다.
2. 저장할 인스턴스의 클래스 형태는 object이므로 CLR은 derived 객체가 object로 업캐스팅이 가능한지 검사 후 업캐스팅 하여 인스턴스 ob에 저장한다.
3. 인스턴스 ob의 타입을 출력 한다. ob는 derived에서 이미 지정된 GetType을 가지고 있으므로 derived 출력
4. 저장할 인스턴스의 클래스 형태는 Base이므로 CLR은 derived 객체가 Base로 다운 캐스팅이 가능한지 검사 후 다운캐스팅 하여 인스턴스 b에 저장한다.
5. 인스턴스 b의 타입을 출력 한다. b는 derived에서 이미 지정된 GetType을 가지고 있으므로 derived 출력
6. 저장할 인스턴스의 클래스 형태는 derived이므로 CLR은 derived 객체가 derived로 다운 캐스팅이 가능한지 검사 후 다운캐스팅 하여 인스턴스 d에 저장한다.
7. 인스턴스 d의 타입을 출력 한다. d는 derived에서 이미 지정된 GetType을 가지고 있으므로 derived 출력
CLR은 매번 캐스팅 할때 인스턴스의 현재 타입과 변환 할 타입의 상속구조, 기본타입을 비교한다.
때문에 캐스팅은 변환 타입에 따라 로드가 걸릴 수 밖에 없다. 하지만 이는 프로그램의 무결성과 보안성을 보장하기 위해 필요한 작업고, Object의 GetType 메서드가 비가상 메서드인 이유와 동일하다.
//System.Object에서 파생 된 base
public class base
{
}
class Program
{
static void Main(string[] args)
{
object ob = 3;
Base b = (Base)ob; // InvalidCastEception 런타임 Error 발생
}
}
위는 InvalidCastException 런타임 에러가 발생하는 구조이다.
이유는 CLR이 int형 타입이 들어간 ob가 연관성 없는 Base Class로 캐스팅을 진행했기 때문이다.
이런 런타임 에러는 프로그램이 죽는 결과를 보여주며 해결방법은 try/catch문으로 예외를 처리해주거나
개발자가 주의하는 방법 뿐이다.
is와 as 연산자를 이용한 캐스팅
위에서 설명했던 명시적 캐스팅은 개발자의 실수로 런타임 에러가 발생할 가능성이 존재한다.
그래서 C#은 is 와 as 연산자를 지원한다.
is : 확인 하고자 하는 인스턴스의 타입 변환 가능유무를 true, false로 반환 해준다.
as : 인스턴스를 변환 하고자 하는 타입으로 변환 시킨다 성공시 변환 타입을 반환 하고 실패시 null을 반환 한다.
is 연산자 예시 코드
if(o is Employee)
{
Employee e = (Employee)o;
}
as 연산자 예시 코드
Employee e = o as Employee;
if(e == null)
return;
조금더 설명을 해보자면 is는 CLR이 변환 하고자 하는 타입과 검사를 수행하고 bool 형식으로만 반환 시킨다.
다시 말해 is 연산자 예시 코드는
1. if(o is Employee)
2. Employee e = (Employee)o;
총 2번 CLR이 타입에 대해 검사를 수행한다.
그래서 성능상으로 바로 as 연산자를 이용해서 변환 후 null 체크만 진행 하는 코드가 더 빠르다.
결론
1. 캐스팅은 CLR이 타입 간 상속 관계, 기본 타입 관계를 비교하여 변환 가능하면 변환, 불가능 하면 InvalidCastException 예외를 던진다.
2. is 보다는 as를 이용하여 null 체크 하는 것이 빠르다.
'Program > C#' 카테고리의 다른 글
const 상수 (1) | 2020.12.20 |
---|---|
값타입의 박싱과 언박싱 (1) | 2020.12.14 |
값 타입, 참조 타입 (0) | 2020.12.13 |
네임스페이스와 어셈블리 (1) | 2020.12.05 |
타입에 대하여1 (1) | 2020.11.29 |