
Effective C# Itme3
C#에서의 형변환
컴파일러의 캐스트 연산자 구문 사용object o = Factory.GetObject(); try { MyType t; t = (MyType)o; // 형 변환 } catch (InvalidCastException) { // 오류 보고 }as 연산자를 사용
object o = Factory.GetObject(); MyType t = o as MyType; if (t != null) { // MyType 타입의 t 객체 사용 } else { // 오류 보고 }is 연산자를 사용
object o = Factory.GetObject(); MyType t; if (o is MyType) { t = o; // MyType 타입의 t 객체 사용 } else { // 오류 보고 }as를 사용할 경우 작성하기 더 쉽고 읽기도 편하다. try/catch 문이 없기 때문에 성능도 좋다.
as 연산자와 캐스팅의 차이점
as, is : 런타임에 객체 타입을 확인하고 필요에 따라 박싱을 수행. 객체를 다른 타입으로 형변환하려면 이 객체는 지정한 타입이거나 혹은 지정한 타입을 상속한 타입이어야 한다. 그 외의 경우는 모두 실패캐스트 : 타입 변환시 형변환 연산자가 개입될 수 있다. 대표적인 형변환 연산자는 숫자 타입에 대한 형변환 연산자(long->short로 변환시 일부 정보를 잃는다.)
사용자가 정의한 타입에서의 문제
public class SecondType { private MyType _value; // 중략 // 사용자 정의 형변환 연산자 // SecondType을 MyType 타입으로 변환한다. public static implicit operator MyType(SecondType t) { return t._value; } }다음 코드에서 Factory.GetObject() 메서드가 앞의 코드에서 정의한 SecondType의 객체를 반환한다고 가정하자
object o = Factory.GetObject(); // o는 SecondType // ver 1 - as 사용 MyType t1 = o as MyType; if (t1 != null) { // MyType 타입의 t1 객체 사용 } else { // 오류 보고 } // ver 2 - 캐스트 사용 try { MyType t2; t2 = (MyType)o; // MyType 타입의 t2 객체 사용 } catch (InvalidCastException) { // 형변환 오류 보고 }두 버전 모두 형변환에 실패한다.
사용자 정의 형변환 연산자에 의해 버전2는 성공했어야 한다.
- 컴파일러는 객체 o가 런타임에 어떤 타입인지를 알 방법이 없다.
- 따라서 컴파일러는 객체 o가 object 타입이라고 생각한다.
- object 타입을 MyType으로 형변환할 수 있는 연산자가 정의됐는지만 확인한다.
- 컴파일러는 객체 o가 MyType 형식인지를 확인하는 코드만 생성한다.
- 런타임에 객체 o는 SecondType 형식의 객체이므로 형변환에 실패한다.
사용자 정의 형변환 연산자는 객체의 런타임 타입이 아닌 컴파일타임 타임에 맞춰 수행된다.
value type/사용자 정의 형변환을 제외한 경우에는 is/as연산자를 사용하는 것이 좋다.