제네릭은 어떻게 구현됩니까?


16

이것은 컴파일러 내부 관점에서 질문입니다.

템플릿 (C ++)이 아닌 제네릭에 관심이 있으므로 C #으로 질문에 표시했습니다. AFAIK는 두 언어의 제네릭이 구현 방식이 다르기 때문에 Java가 아닙니다.

제네릭이없는 언어를 볼 때 매우 간단합니다. 클래스 정의의 유효성을 검사하고 계층 구조에 추가하면됩니다.

그러나 제네릭 클래스로 무엇을해야합니까? 더 중요한 것은 참조를 처리하는 방법입니다. 정적 필드가 인스턴스화마다 단일인지 확인하는 방법 (즉, 일반 매개 변수가 분석 될 때마다).

전화가 있다고 가정 해 봅시다.

var x = new Foo<Bar>();

Foo_Bar계층 에 새 클래스를 추가 합니까?


업데이트 : 지금까지 2 개의 관련 게시물 만 찾았지만 "자신이 직접 수행하는 방법"이라는 의미에서 많은 세부 사항을 다루지 않았습니다.


완전한 답변이 흥미로울 것이라고 생각하기 때문에 공감. 작동 방식에 대한 아이디어가 있지만 정확하게 대답하기에 충분하지 않습니다. C #의 제네릭이 각 제네릭 유형의 특수 클래스로 컴파일되지 않는다고 생각합니다. 런타임에 해결되는 것 같습니다 (제네릭을 사용하면 눈에 띄는 속도가있을 수 있습니다). 에릭 리퍼 트가 차임 할 수 있을까?
KChaloux

2
@KChaloux : MSIL 수준에는 제네릭에 대한 설명이 있습니다. JIT가 실행되면 일반 매개 변수로 사용되는 각 값 유형 및 모든 참조 유형을 포함하는 하나 이상의 기계 코드 세트에 대해 별도의 기계 코드가 작성됩니다. MSIL에서 일반 설명을 유지하면 런타임에 새 인스턴스를 만들 수 있기 때문에 정말 좋습니다.
벤 Voigt

P : @ 벤 실제로 질문에 대답하지 않은 이유의 그
KChaloux

아직 주변에 있는지 확실하지 않지만 어떤 언어로 컴파일 하고 있습니까 ? 그것은 제네릭을 구현하는 방법에 많은 영향을 미칩니다. 프런트 엔드에서 일반적으로 접근 한 방식에 대한 정보를 제공 할 수 있지만 백엔드는 크게 다를 수 있습니다.
Telastyn

@Telastyn, 그 주제에 대해서는 확실히 :-) C #에 가까운 것을 찾고 있습니다. 제 경우에는 PHP로 컴파일 하고 있습니다 (농담 없음). 당신이 당신의 지식을 공유하면 감사하겠습니다.
greenoldman

답변:


4

정적 필드가 인스턴스화마다 단일인지 확인하는 방법 (즉, 일반 매개 변수가 분석 될 때마다).

각 일반 인스턴스화에는 정적 필드가 저장되는 고유 한 이름의 MethodTable 사본이 있습니다.

전화가 있다고 가정 해 봅시다.

var x = new Foo<Bar>();

Foo_Bar계층 에 새 클래스를 추가 합니까?

클래스 계층 구조를 런타임에 실제로 존재하는 구조로 생각하는 것이 유용하지 않다는 것은 확실합니다. 논리적 구성입니다.

그러나 각각 기본 클래스에 대한 간접 포인터가있는 MethodTables를 고려하여이 계층을 구성하면 그렇습니다. 그러면 계층에 새 클래스가 추가됩니다.


고마워요. 재미있는 부분입니다. 정적 필드는 가상 테이블과 유사하게 해결됩니다. 각 유형마다 항목을 보유하는 "전역"사전에 대한 참조가 있습니까? 따라서 2 개의 어셈블리를 사용하여 서로를 알지 못하고에서 Foo<string>두 개의 정적 필드 인스턴스를 생성하지 않습니다 Foo.
greenoldman

1
@greenoldman 음, 가상 테이블과 비슷하지는 않습니다. MethodTable은 정적 디스패치와 가상 디스패치에 사용되는 형식의 메서드에 대한 참조를 모두 보유합니다 (그래서 MethodTable이라고 함). 그리고 CLR에는 모든 MethodTable에 액세스하는 데 사용할 수있는 테이블이 있어야합니다.
svick

2

거기에 실제 두 가지 구체적인 질문이 있습니다. 완전히 이해하기 위해 추가 관련 질문 (이 질문에 대한 링크가있는 별도의 질문)을 추가하고 싶을 것입니다.

정적 필드는 일반 인스턴스마다 어떻게 별도의 인스턴스가 제공됩니까?

제네릭 형식 매개 변수와 관련이없는 정적 멤버의 경우 이것은 매우 쉽습니다 (일반 매개 변수에서 값으로 매핑 된 사전 사용).

유형 매개 변수와 관련된 멤버 (정적 또는 비정의)는 유형 삭제를 통해 처리 할 수 ​​있습니다. 가장 강한 제약 조건이 무엇이든 사용하십시오 (종종 System.Object). 유형 정보는 컴파일러 유형 검사 후에 지워 지므로 런타임 유형 검사가 필요하지 않음을 의미합니다 (런타임에 인터페이스 캐스트가 여전히 존재할 수 있음).

각 일반 인스턴스가 유형 계층 구조에 별도로 표시됩니까?

.NET 제네릭에는 없습니다. 유형 매개 변수에서 상속을 제외하기로 결정했기 때문에 일반의 모든 인스턴스가 유형 계층에서 동일한 지점을 차지합니다.

기본 클래스에서 이름을 찾지 못하면 놀라 울 정도로 놀라운 결정이었을 것입니다.


내 문제는 템플릿 측면에서 생각을 벗어날 수 없다는 것입니다. 예를 들어 - 달리 템플릿 제네릭 클래스가 되어 완전히 컴파일. 이것은이 클래스를 사용하는 다른 어셈블리에서 어떻게됩니까? 이미 컴파일 된 메소드가 내부 캐스팅으로 호출됩니까? 나는 제네릭 제약에 의존 할 수 의심 - 오히려 인수에, 그렇지 Foo<int>Foo<string>함께 동일한 데이터를 칠 것이다 Foo승 / O를 제약.
greenoldman

1
@greenoldman : 실제로 특수하게 처리되기 때문에 1 분 동안 값 유형을 피할 수 있습니까? 당신이있는 경우 List<string>List<Form>이후 다음, List<T>내부적 유형의 멤버가 T[]와에 아무런 제약이없는 T다음, 당신이 실제로거야하면 해당를 조작 기계 코드입니다 object[]. 그러나 T인스턴스 만 인스턴스에 배치 T되므로 추가 유형 확인없이 나오는 모든 항목을 반환 할 수 있습니다 . 반면에을 가지고 있으면 ControlCollection<T> where T : Control내부 배열 T[]이됩니다 Control[].
Ben Voigt

제약 조건이 내부 형식 이름으로 사용되지만 클래스가 실제로 사용될 때 캐스팅이 사용된다는 것을 올바르게 이해하고 있습니까? 좋아, 나는 그 모델을 이해하지만 Java가 C #이 아니라 그것을 사용한다는 인상을 받았다.
greenoldman

3
@greenoldman : Java는 소스-> 바이트 코드 변환 단계에서 유형 삭제를 수행합니다. 검증자가 일반 코드를 검증 할 수 없습니다. C #은 바이트 코드-> 기계 코드 단계에서 수행합니다.
Ben Voigt

@BenVoigt 일부 정보는 제네릭 형식에 대한 Java로 유지됩니다. 그렇지 않으면 소스가없는 제네릭 사용 클래스에 대해 컴파일 할 수 없기 때문입니다. 바이트 코드 시퀀스 자체 AIUI에 ​​보관되지 않고 클래스 메타 데이터에 보관됩니다.
Donal Fellows

1

그러나 제네릭 클래스로 무엇을해야합니까? 더 중요한 것은 참조를 처리하는 방법입니다.

컴파일러의 프런트 엔드에서 일반적인 방법은 제네릭 형식 ( List<T>)과 바운드 제네릭 형식 ( List<Foo>)의 두 가지 유형의 인스턴스 유형을 갖는 것 입니다. 제네릭 형식은 존재하는 함수, 필드 및 정의 된 위치에 대한 제네릭 형식 참조를 정의합니다 T. 바운드 제네릭 형식에는 제네릭 형식에 대한 참조와 형식 인수 집합이 포함됩니다. 여기에는 구체적인 유형을 생성하고 일반 유형 참조를 Foo유형 인수가 무엇이든 대체하는 데 필요한 충분한 정보가 있습니다 . 이러한 유형의 구별은 유형 유추를 수행 할 때 중요하며 List<T>vs 를 추론해야합니다 List<Foo>.

템플릿과 같은 제네릭 (다양한 구현을 직접 구축)을 생각하는 대신 함수형 언어 유형 생성자 (제네릭 인수가 함수를 인자로 제공하는 함수)와 같이 생각하는 것이 도움이 될 수 있습니다.

백엔드에 관해서는, 나는 정말로 모른다. 제네릭에 대한 모든 작업은 CIL을 백엔드로 지정했기 때문에 지원되는 제네릭으로 컴파일 할 수있었습니다.


대단히 감사합니다 (다중 답변을받을 수없는 것이 유감입니다). 내 경우에는 - 내가 거의 정확하게 단계는 것을했다는 것을 듣고 대단한 List<T>동안, 실제 유형 (정의를) 보유하고 List<Foo>내 접근 홀드의 선언 (뿐만 아니라 용어 조각 주셔서 감사합니다) List<T>물론 지금에 바인딩의 ( Foo) 대신 T.
greenoldman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.