2011-03-17 3 views
27

코드를 컴파일 할 때 생성되는 템플릿과는 달리 JIT가 제네릭을 컴파일한다는 것을 알고 있습니다.
리플렉션을 사용하여 런타임에 새로운 제네릭 형식을 만들 수 있습니다.
물론 제네릭의 제약 조건에 영향을 미칠 수 있습니다. 어느 의미 구문 분석기를 이미 통과했습니다.제네릭은 JIT 컴파일러에 의해 어떻게 컴파일됩니까?

누군가 처리 방법을 설명 할 수 있습니까? 그리고 정확히 어떻게됩니까?
(코드 생성 및 의미 검사 모두)

+3

제약 조건은 컴파일러에서 강제로 적용되는 것이 아니라 지터가 검사합니다. 제네릭에는별로 중요하지 않은 부분이 몇 가지 있는데, 어떻게 ngen-ed를 얻는 지 특히 흥분됩니다. 그것들은 5 년이 걸렸습니다. –

답변

35

나는 Generics in C#, Java, and C++: A Conversation with Anders Hejlsberg을 읽는 것이 좋습니다.

Qn 1. JIT 컴파일러는 어떻게 generics를 컴파일합니까?

앤더스 헤 즐스 버그 : 인터뷰에서

는 목록, 또는 다른 제네릭 형식을 컴파일 할 때 [...]를 CLR [공용 언어 런타임, 에서 , 그것은 아래로 컴파일 모든 일반 유형과 마찬가지로 IL [중간 언어] 및 메타 데이터 IL 및 메타 데이터에는 물론 매개 변수가 있다는 것을 알고있는 추가 정보가 포함되어 있지만 원칙에 따르면 일반 유형은 을 으로 컴파일하는 방식으로 컴파일합니다. 런타임에 응용 프로그램이 List에 첫 번째 참조 을 작성하면 시스템에서 List<int>을 이미 요청한 경우 이 표시됩니다. 그렇지 않은 경우 List<T> 및 유형 인수 int의 IL 및 메타 데이터를 피드합니다. JITer 인 IL을 JIT 처리하는 과정에있는 도 을 사용하여 type 매개 변수를 대체합니다.

는 [...]

지금, 우리가 그 다음 일은 값이 유형-등 List<int>, List<long>, List<double>, List<float>로 - 우리가 실행 기본 코드의 고유의 복사본을 만들 수있는 모든 유형 인스턴스화입니다. 따라서 List<int>은 자체 코드를 얻습니다. List<long>은 자체 코드를 가져옵니다. List<float>은 자체 코드를 가져옵니다. 모든 참조 유형에 대해 우리는 코드를 공유합니다. 왜냐하면 대표적으로 이 동일하기 때문입니다. 그것은 단지 포인터 일뿐입니다.


QN 2 일

새로운 제네릭 형식 이 반사를 사용하여 런타임에서 생성 될 수 있다는 것이다. 물론 generic의 제약 조건 인 에 영향을 미칠 수 있습니다. 어느 이미 의미 파서를 통과 시켰습니다. 누군가가 을 어떻게 처리 할 수 ​​있습니까?

기본적으로 IL는 '정적으로 구성된'유형을 위해 할 수있는 단지 C# 컴파일러와 같은 런타임에 제네릭 형식 '을 동적으로 생성'의 CLR이 제약 조건을 확인할 수 있습니다 일반적인 유형의 높은 수준의보기를 유지 컴파일 타임에 C# 소스 코드.

앤더스 헤 즐스 버그 : 여기

다른 조각 (강조 광산)의 [...] 제약으로, 당신은 동적 코드의 체크 아웃 및 그것에서 검증 을 할 수 있다고 호이스트 수 있습니다 컴파일 시간은 이거나로드 시간. K가 에 IComparable을 구현해야한다고 말하면 몇 가지 일이 발생합니다. K 유형의 모든 값이 인 경우 의미가있는 인터페이스에 인터페이스가 구현되어 있기 때문에 캐스트없이 인터페이스 메소드에 직접 액세스 할 수 있습니다. 당신이 시도하고 는 해당 유형의 인스턴스를 만들 때마다, 컴파일러는 당신이 K 인수로 제공 모든 유형이 에서 IComparable을 구현하는 것을 확인합니다, 그렇지 않으면 당신은 컴파일 시간 오류가 발생합니다. 리플렉션으로 작업하는 경우 예외가 발생합니다.

브루스 Eckel : 당신은 컴파일러와 런타임을 말했다.

앤더스 헤 즐스 버그 : 컴파일러 검사 을, 그러나 당신은 또한 반사 런타임시에 그 일을 할 수 있고, 다음 시스템을 확인합니다. 앞서 말했듯이 컴파일시에 수행 할 수있는 모든 것, 도 런타임에 리플렉션으로 수행 할 수 있습니다.

2

참조 유형 제네릭은 모두 과 동일합니다. 유형입니다. 값 유형 제네릭은 을 개별적으로 인스턴스화합니다.

참조 유형은 모두 실제로 Object 참조 (4 또는 8 바이트)이지만 값 유형은 다르고 스택 레이아웃 차이 등으로 인해 단일 코드 조각으로 처리 할 수 ​​없기 때문에 이러한 결과가 발생합니다. 따라서 다중 값 유형이있는 일반 유형의 사본은 메모리 사용량을 많이 증가 시키지만 참조 유형을 사용하여 여러 사본을 인스턴스화하는 것은 그렇지 않습니다.

+1

그들은 같은 유형이 아닙니다. 그것들은 멤버 함수 (메쏘드)를위한 동일한 기계 코드를 공유하지만 ... 각각은 정적 멤버 변수의 복사본을 가진 구별 된 타입이다. –

+0

@BenVoigt : 맞아 ... 설명해 주셔서 고마워요. – Mehrdad

관련 문제