DEV Community

Composite
Composite

Posted on

1 2

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

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 링크에서 설명했듯이 "성능"이다. 단순히 성능이 빨르다고 했다면 제네릭이 쓸 필요가 없지만,
제네릭은 박싱/언박싱으로 인한 타입 검증 과정을 줄여줌으로써 성능상 이득을 내는 건 닷넷 개발자라면 알 것이다.
바로 이런 원리를 익명 클래스에서도 적용했다고 보면 된다. 납득 ㅇㅇ?

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

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay