DEV Community

Composite
Composite

Posted on

닷넷에 있는 익명 타입은 왜 제네릭이냐?

2015-04-03 10:18:50 from blog.hazard.kr

닷넷 개발자로 귀환하고 첫 닷넷글이네.

5년전의 MSDN 글을 보고 5년 후에 쓴 내가 조금 처량해 보이지만...

여태까지 익명 클래스 사용하는 법이야 당연히 많지만, 왜인지 해소를 해준 글은 본 적이 없다.
MSDN 글이 내 궁금증을 해소해주는 유일한 곳이긴 하다. 물론 MS에서 만들었으니 MSDN 에 올라는거야 당연하긴 하지만.

어쨌든, 내가 4년전에 익명 타입을 알아내는 방법 글을 올렸었다.
와.. 이때동안 난 자바했네 시발.

어쨌든 여기서 특징이 있다면...

  • CompilerGenerated 특성이 적용됩니다.
  • 제네릭 타입입니다. 의외네요.
  • 클래스 이름에 AnonymousType 라는 문구가 포함됩니다.
  • 클래스 이름 머릿말에 C# 의 경우 <>, VB의 경우 VB$ 로 시작됩니다.
  • 클래스는 public 이 아닙니다.

이렇게 기재되어 있다. 뭐 다른 이유야 구분짓고, 게다가 어자피 지역 변수니 internal 클래스는 이해 한다.
근데 왜 제네릭일까? 그래서 위 MSDN 블로그에 갔다.

자. 익명 클래스 하나 만들었다고 치자.

var x = new { A = "hello", B = 123.456 };
Enter fullscreen mode Exit fullscreen mode

그리고 이걸 빌드 후 리플렉션 툴로 까보면 해괴망측한 클래스 정의가 나온다.

.class '<>f__AnonymousType0`2'< '<A>j__TPar','<b>j__TPar'>
Enter fullscreen mode Exit fullscreen mode

여기서 익명 클래스의 특징이 나오는데, 바로 속성 수만큼 제네릭 타입 개수가 나온다는 것이다.
예를 들어 속성이 2개면, 제네릭에 들어갈 타입도 2개란 소리다.
MSDN에서는 컴파일 후 사용자 친화적인 코드로 표현하면 아래와 같은 코드가 나온다고 한다.

[CompilerGenerated]
internal sealed class Anon0<ta , TB>
{
    private readonly TA a;
    private readonly TB b;
    public TA A { get { return this.a; } }
    public TB B { get { return this.b; } }    
    public Anon0(TA a, TB b)
    { this.a = a; this.b = b; }
    // 여기에 object의 Equals, GetHashCode 와 ToString 메소드 덮겠지.
}
Enter fullscreen mode Exit fullscreen mode

sealed 키워드까지 붙었다. 물론 굳이 저 클래스를 상속할 이유가 있겠는가?
그렇다면 첫번째 코드의 익명 클래스로 선언했을 때 컴파일된 클래스 결과물은 이렇다.

자, 그렇다면 익명 클래스에서 자신이 사용한 클래스를 적용한다면?
보통은 당연히 public이라면 어자피 제네릭에 들어가니 상관은 없다.
그런데... 이런 경우가 있다.

public class B 
{
    protected class P {}
}

Enter fullscreen mode Exit fullscreen mode

B 클래스 내에 P 클래스가 있다. 당연히 P 클래스는 B 클래스와 B를 상속한 클래스 내에서만 접근 가능하다.
그런데 그걸 익명 클래스를 통해 밖으로 끄집어내기 시작한다.

class D1 : B
{
    void M() { var x = new { P = new B.P() }; }
}

class D2 : B
{
    void M() { var x = new { P = new B.P() }; }
}

Enter fullscreen mode Exit fullscreen mode

이렇게 하면 어떻게 생성되느냐. 아래와 같다.

class D1 : B
{
    [CompilerGenerated]
    ??? sealed class Anon0 { public P P { get { ... } } ... }
    void M() { var x = new { P = new B.P() }; }
}
Enter fullscreen mode Exit fullscreen mode

뭐... 그러고 보니 P 클래스가 공개적 접근이 안되는데 B의 M 메소드로 공개하려 하니 골치가 아프지 않은가.
그래서 아예 접근 못하는 클래스를 복사해 익명 클래스로 재생성한 꼴이 된다.
이 부분에 대해선 필자도 좀 더 공부해봐야 겠다.

자. 일단 이렇게 나온다. 간단히 정리하자면 익명 클래스는 속성 타입들의 제네릭 클래스다.
그 이유는 맨 위 MSDN 링크에서 설명했듯이 "성능"이다. 단순히 성능이 빨르다고 했다면 제네릭이 쓸 필요가 없지만,
제네릭은 박싱/언박싱으로 인한 타입 검증 과정을 줄여줌으로써 성능상 이득을 내는 건 닷넷 개발자라면 알 것이다.
바로 이런 원리를 익명 클래스에서도 적용했다고 보면 된다. 납득 ㅇㅇ?

그럼 이만 물러나겠다. 뿅.

Top comments (0)