Welcome to Dynamic C#(12) - dynamic은 외로운 아이.

C# 2010. 1. 18. 09:00 Posted by 알 수 없는 사용자

- 뭐시 외로운 아이여? 스타아닌겨?

네. 확실히 C# 4.0의 가장 큰 키워드는 Dynamic이기 때문에, dynamic은 스타일지도 모르겠습니다. 하지만, 화려한 모습뒤에 감쳐진 그들의 일상사는 때때로 자살같은 비극적인 사건을 통해서 세간에 알려지곤 하죠. 그럴때마다 세삼스럽게 사람들은 화려한 일상뒤의 모습은 변비때문에 우울해하는 것 같이, 보통사람과 전혀 다르지 않음을 재확인 합니다..... 왜 이런 헛소리를 또 하고 있을까요-_-;;; 아무튼. dynamic은 초큼 외로운 아이입니다. 증거를 제시해드리죠.



그림1. 출처 : http://blogs.msdn.com/cburrows/archive/2008/11/06/c-dynamic-part-iv.aspx

네. 다른 타입들은 System.Object로 부터 아주 사이좋게 이리저리 연결되어 있습니다만, dynamic은 천상천하유아독존입니다. 그저 혼자 있을 뿐이지요. 어린이집에서도 유별난 애들은 꼭 걔네들 기분에 잘 맞춰줘야 해서 선생님들이 고생을 하기도 하는데요. dynamic역시 독특한 면을 갖고 있습니다. 지난 포스트에 이어서 dynamic의 형변환 룰에 대해서 알아보면 아래와 같습니다.

1. dynamic에서 dynamic으로 동일한 형변환이 가능
2. 모든 참조형 타입에서 dynamic으로 암시적인 참조형변환이 가능
3. 모든 값형 타입에서 dynamic으로 암시적인 박싱형변환이 가능
4. dynamic에서 모든 참조형 타입으로 명시적인 참조형변환이 가능
5. dynamic에서 모든 값형 타입으로 명시적인 언박싱 형변환이 가능
리스트1. dynamic에서 다른 타입으로 형변환 가능여부.

  아래부분에 줄로 그어 버린 부분은 정식버전이 출시되면서 개념이 바뀐 부분들입니다. 그리고 밑에서 설명드리는 '대입형변환'이라는 용어도 여전히 의미가 있는지 불분명합니다. 다만, C# 4.0 명세서에 보면 '대입형변환'이라는 개념이 없는 걸로 봐서는 설명을 위해서 도입한 개념이 아닌가 싶은데요, 이에 관해서 Chris Burrows에게 질문을 남겨놨는데요, 답이 오면 바로 업데이트 하겠습니다. 바뀐 내용에 대해서는 이 글을 참조하시기 바랍니다.

매우 직관적으로 보이긴 하지만, 좀 생각해보면 이상한 점들이 발견됩니다. 그 첫번째가 바로 dynamic에서 object로 암시적인 형변환이 없다는 사실인데요. 위에서 1, 4번에서 언급했듯이 dynamic에서 dynamic을 제외한 모든 참조형타입으로 암시적인 형변환이 없다고 하고 있습니다. 그 이유는 연산을 하는 도중에 둘을 구분해내기가 매우 어렵기 때문이라고 합니다. 근데, 아래와 같은 코드가 컴파일 되고 실행되는 걸 확인할 수 있습니다.

dynamic d = null;
object o = d;

이건 분명히 암시적 형변환 처럼 보이는데, 왜 이게 컴파일이 되는 걸까요? 사실, 두번째줄은 암시적 형변환이 아니라 대입 형변환입니다. 대입 형변환은 또 뭘까요?

그림 2. 출처 : http://blogs.msdn.com/cburrows/archive/2008/11/11/c-dynamic-part-v.aspx

위 그림을 보시면, 형변환이 총 3가지로 분류가 되는 걸 확인하실 수 있습니다. 대입 형변환은 명시적 형변환과 암시적 형변환의 사이에 위치해 있는데요. 모든 대입 형변환은 사실 명시적 형변환이며, 모든 암시적 형변환은 대입 형변환 인거죠. 왜 이런 걸 새로 도입했어야 할까요? 사실 C# 4.0작업을 하면서 dynamic에서 다른 타입으로 암시적 형변환 도입을 검토했었다고 합니다. 그런데, 이렇게 하게 되면 문제가 생기는데요. 바로, dynamic을 통해서 아무타입에서 아무타입으로 형변환이 가능하기 때문입니다. 이 문제를 오버로드 판별을 예로 들어서 설명해보겠습니다.

public class C
{
    public static void M(int i){}

    public static void M(string s){}
   
    static void Main(string[] args)
    {
        dynamic d = GetSomeDynamic();
        C.M(d);
    }
}

코드1. 만약 암시적 형변환이 가능하다면?

위와 같은 코드가 있다고 할때요, 과연 어떤 메서드가 실행되어야 할까요? dynamic에서 모든 타입으로 암시적 형변환이 있다면, dynamic에서 int도 dynamic에서 string도 가능한 상황이 됩니다. 물론, dynamic에서 object같이 dynamic에서 int보다 더 나은 걸 찾을 수도 있겠지만, 그렇지 않은 경우가 훨씬 많이 발생하게 됩니다. 이런 모호함 때문에 dynamic에서 다른 타입으로 형변환을 할때는 명시적으로 선언을 하게 제한을 둔 거죠.

그렇다면, 대입 형변환은 또 뭘까요?

1. dynamic에서 모든 참조형 타입으로 대입 참조 형변환이 가능
2. dynamic에서 모든 값형 타입으로 대입 언박싱 형변환이 가능
리스트2. 대입 형변환의 설명

[리스트1]에서 4,5번을 보면 명시적 형변환에 대해서 이야기 하고 있죠? 사실은 그 명시적 형변환이 바로 이 대입 형변환을 말하는 겁니다. 모든 대입 형변환은 명시적 형변환이라고 말씀드렸던 걸 떠올리시면 고개가 절로 끄덕끄덕....교회 다니시는 분들은 교회로 끄덕끄덕 하실겁니다. 그리고 리스트2의 모든 형변환과 암시적 형변환을 모두 합하면 바로 대입 형변환이 되는 거죠.


- 그래그래 어디 계속 해봐.

대입이 일어나는 곳이 바로 컴파일러가 대입 형변환을 시전하는 곳입니다.

dynamic d = GetSomeDynamic();
Worksheet ws = d; //대입 형변환

이거 말고도, 대입 비스무리한 것들은 모두 대입 형변환을 사용합니다. return과 yield 그리고 프로퍼티와 인덱서, 배열 초기화구문, 그리고 foreach나 using같은 구문말이죠.

return d; //return할 타입으로 대입 형변환
yield return d; //반복자의 타입으로 대입 형변환
foo.Prop; //Prop의 타입으로 대입 형변환
foo[1] = d; //인덱서의 타입으로 대입 형변환
bool[] ba = new bool[] { true, d }; //bool로 대입 형변환
foreach(var x in d) {} //IEnumerable로 대입 형변환
using (d) {} //IDisposable로 대입 형변환
리스트3. 대입 형변환이 어디어디서 끼어드는지!

하지만, 이런 대입 형변환을 사용하지 않는 곳 중에 하나가 오버로드 판별입니다. [코드1]에서 보셨듯이 만약에 메서드를 호출하는데 대입 형변환을 적용하게 되면, 매번 메서드를 호출할때마다 모호함때문에 캐고생을 하게 될겁니다. 하지만, 대입 형변환을 적용하지 않는다고 해도, [코드1]은 제대로 컴파일 되지 않을거 같습니다. 왜냐면, d의 타입인 dynamic에서 C의 두 오버로드가 받는 파라미터 타입인 int와 string으로 형변환이 불가능 하기 때문입니다. 하지만, 이런 코드가 컴파일 되고 잘 돌아가야만 하니깐, 바로 지난 포스트에서 언급했던 유령 메서드가 끼어들게 되는거죠.


- 마치면서

어찌 퍼즐 조각이 좀 맞아 들어가시나요? 저도 글을 쓰면서 다시한번 자세히 읽다보니 퍼즐조각이 조금씩 맞아들어가는 느낌이 드는데요. 꼭 무슨 그것이 알고싶다에서 사건 조사하는 거 같은 기분이네요-_-. 그럼 다음 포스트에서 뵙져!!!


- 참고자료

1. http://blogs.msdn.com/cburrows/archive/2008/11/06/c-dynamic-part-iv.aspx
2. http://blogs.msdn.com/cburrows/archive/2008/11/11/c-dynamic-part-v.aspx