2010-11-23 3 views
2

런타임에 Reflection.Emit을 사용하여 유형을 구축 중입니다. 최종 사용자는 기본 유형과 새로운 유형이 지원해야하는 인터페이스를 제공합니다. 인터페이스에 기본 유형이 지원할 수없는 멤버가있는 경우 정적 필드에 저장된 대리자를 호출하는 스텁 메서드를 만듭니다 (참조 또는 매개 변수없이 15 개 이하의 매개 변수를 사용하는 비 제너릭 메서드 만 지원합니다. 이 제한 사항으로 문제를 제기하지 마십시오. 대리자는 사용자가 형식을 만들기 전에 제공 할 수있는 baseType의 첫 번째 매개 변수를 사용합니다.유형이 인터페이스를 지원할 수있는 최선의 방법은 무엇입니까? (Duck-Typing)

그러나 형식으로 만족할 수있는 인터페이스 멤버에 대한 대리자 스텁을 만드는 것을 피하고 싶습니다. 예 : 난 당신이 내 빌더 여기 new[]{typeof(IDuck)}Goose에 보낸 경우, 나는 거위로 void Quack()에 대한 스텁을 생성하지 않습니다 싶습니다

public class Goose 
{ 
    public void Quack() 
    { 
     // quack implementation details go here. 
    } 
} 

public interface IDuck 
{ 
    void Quack() 
} 

인터페이스를 만족시킨다.

Goose가 IDuck을 구현하지 않아서 인터페이스 매핑이 작동하지 않아서 TypeBuilder이 생성해야하는 유형에서 인터페이스 매핑을 위해 새로 빌드 된 유형을 요청할 수 없습니다.

어떻게 원격으로 효율적으로 해결할 수 있습니까? 공개적으로 표시되는 멤버 만 조사해야하며 동일한 유형의 인터페이스를 명시 적으로 구현하는 유형은 대상으로 사용해서는 안된다고 생각할 수 있습니다. (예 : 거위가 void IGoose.Quack()으로 구현 된 경우 void IDuck.Quack()의 대상으로 간주해서는 안 됨). (어쨌든 BindingFlags.Public | BindingFlags.Instance은 이러한 요소를 필터링하는 데 충분해야합니다.)

+0

[Duck Typing Project] (http://www.deftflux.net/blog/page/Duck-Typing-Project.aspx)를 사용해 보았습니까? – cdhowie

+0

이것은 재미있는 접근법입니다. 형식을 바꿔야 할 때 정확하게 일치시켜야합니다. –

답변

0

리플렉션을 통해 공개 구현 된 모든 멤버를 리플렉션을 통해 해시 집합으로 가져와야합니다 (MemberInfo는 GetHashCode를 구현합니다. 다른 유형의 멤버를 비교할 수 있는지 모르겠지만 해시 객체가 필요한 서명 유형 및 이름), 새로운 인터페이스의 멤버를 반복 할 때, 해시 셋에 존재하지 않는 경우에만 스텁 코드를 생성합니다.

CreateType을 호출 할 때까지 멤버가 있기 전에 TypeBuilder에서 인터페이스를 선언하는 것은 문제가되지 않으며 기본 형식이 사용자로만 구현하는 다른 인터페이스 새 인터페이스와 일치하는 회원의 서명에 신경을 써야합니다.

결과 유형을 기본 형식 인 & 기본 유형으로 캐시하는 한 모든 성능이 현저히 떨어지지 않아야합니다.

0

효율적으로 MemberInfos의 이름과 서명을 비교하는 것이 효과적입니다. MemberInfo에서 ToString을 호출하여 멤버의 이름과 서명이 포함 된 문자열을 가져올 수 있습니다. 이 문자열을 사용하여 두 멤버가 서명이 동일한 지 여부를 확인할 수 있습니다. 문자열을 HashSet에 넣으면 비교가 매우 효율적입니다.

ToString이 비교 가능한 서명 문자열을 작성한다는 사실은 MemberInfo 개체를 serialize하고 deserialize하기 위해 .NET Framework에서 내부적으로 사용되지만 AFAIK는 실제로 문서화되지 않았습니다. 따라서이 문서화되지 않은 동작에 의존하고 싶지 않은 경우 자체 서명 문자열을 작성하여 비교할 수 있습니다. 그러나 일단 generic 형식 매개 변수를 고려하면이 작업이 상당히 복잡해질 수 있습니다.

관련 문제