2013-09-03 3 views
8

나는 또 다른 유형의 하위이 될 수있는 형식 매개 변수를 강제하는 방법을 알고 다른 타입의?구속 유형 매개 변수는

public interface IMapping<T2> 
{ 
    public void IncludeMappingOf<T1>() 
     where T2 : T1; // <== doesn't work 
} 
... 

var mapping = MapManager.Find<Truck>(); 

// Truck inherits Vehicle  
// Would like compiler safety here: 
mapping.IncludeMappingOf<Vehicle>(); 

mapping.Serialize(new TonkaTruck()); 

현재, 나는 IncludeMappingOf 내부 IsSubclassOf를 사용하여 런타임에 T1 및 T2를 비교하는 데 문제가 있습니다. 컴파일에 안전한 솔루션이 바람직합니다. 어떤 아이디어?

편집 : 예를 덜 디자인 적으로 변경했습니다.

참고 : 참고 : 연결된 질문은 매우 유사하지만 적합한 대답은 제공되지 않습니다. 바라기를이 질문은 저것에 또한 어떤 빛을 비춰 줄 것이다.

EDIT # 2 :

간단한 예 :

public class Holder<T2> 
{ 
    public T2 Data { get; set; } 

    public void AddDataTo<T1>(ICollection<T1> coll) 
     //where T2 : T1 // <== doesn't work 
    { 
     coll.Add(Data); // error 
    } 
} 

... 
var holder = new Holder<Truck> { Data = new TonkaTruck() }; 
var list = new List<Vehicle>(); 
holder.AddDataTo(list); 

컴파일러 : 인수 유형 'T2'는 타입 'T1'을 파라미터에 할당 아니다. 예, 필자는 T2가 매개 변수 유형 T1에 할당 가능한 경우 만 허용하도록 컴파일러를 얻으려고합니다.

+3

아주 흥미로운 질문이지만, 여기에 디자인 문제가있을 수 있다는 느낌을 떨칠 수 없는데 왜 '트럭 매핑'이 '맵핑'대신 'VehiculeMapping'을 상속하지 않는 것입니까? 나는 트럭 맵핑이 좀 더 일반적인 차량 맵핑의 특화된 버전인지 또는 뭔가 빠져있는 것처럼 들리는가요? –

+0

강력하게 관련 (중복) : [C# 제네릭 메서드 형식 매개 변수를 "포함 할 수있는 클래스"형식 매개 변수로 제한 할 수 있습니까?] (http://stackoverflow.com/questions/11255558/is-it-possible -to-constrain-ac-sharp-generic-method-type-as-assignab) –

+0

@ SimonRapilly : 아마도 맞을 것이다. 이것은 문제를 설명하는 데 도움이되는 고안된 예제입니다. 예제를 약간 변경했습니다. – CSJ

답변

1

확장 방법을 사용하여 원하는대로 가깝게 이동할 수 있습니다.당신 홀더 예제를 사용하여이 될 것이다 :

var holder = new Holder<Truck> { Data = new TonkaTruck() }; 
var list = new List<Vehicle>(); 
holder.AddDataTo(list); 

매핑 예는이 인터페이스는 사실에 의해 복잡 : 다음 오류없이 컴파일하는 코드를 호출하여 예를 허용

public class Holder<T2> 
{ 
    public T2 Data { get; set; } 
} 

public static class HolderExtensions 
{ 
    public static void AddDataTo<T2, T1>(this Holder<T2> holder, ICollection<T1> coll) 
     where T2 : T1 
    { 
     coll.Add(holder.Data); 
    } 
} 

합니다. 기존 인터페이스에서 확장 메소드를 구현할 방법이 없으면 인터페이스에 구현 메소드를 추가해야 할 수도 있습니다. 즉, 런타임 검사가 여전히 필요하지만 호출자는 올바른 구문을 가져 와서 시간 검사를 컴파일 할 수 있습니다.

public interface IMapping<T2> 
{ 
    void IncludeMappingOf(Type type); 
} 

public static class MappingExtensions 
{ 
    public static void IncludeMappingOf<T2, T1>(this IMapping<T2> mapping) 
     where T2 : T1 
    { 
     mapping.IncludeMappingOf(typeof(T1)); 
    } 
} 

불행히도이의 IncludeMappingOf 유형 T1의 매개 변수 때문에 유형 매개 변수를 추론 할 수없는 : 그건 뭔가처럼 될 것입니다. 당신은 그것을 호출 할 때 두 가지 유형을 지정하는 강제 : 종종 매개 변수 나 유창하게하는 API 인 방법/클래스 매개 변수 (예 : truckMapping.IncludeMappingOf(vehicleMapping)), 변화를 포함하도록 API를 변경하여 해결할 수 있습니다

var mapping = MapManager.Find<Truck>(); 
mapping.IncludeMappingOf<Truck, Vehicle>(); 
mapping.Serialize(new TonkaTruck()); 

체인 (즉, mapping.Of<Vehicle>().Include())을 생성합니다.

+0

이것은 조금 영리하지는 않지만 (클래스에 대한 논리가 이제 두 클래스에 걸쳐 확산되었지만) 매우 영리합니다. 그러나 목표를 달성합니다! – CSJ

4

선언 모두 일반적인 유형과 클래스 (인터페이스)에서 일반 제약 수준 :

public interface IMapping<T1, T2> where T2 : T1 
{ 
    void IncludeMapping(IMapping<T1, T2> otherMapping); 
} 
+1

이것은 클래스의 모든 인스턴스가 항상 선언 된대로'T3'을 사용해야 함을 의미합니다. 원래의 의도는 객체를 선언/인스턴스화 한 다음'T2 '파생 된 유형이었다. 게다가,이 질문은 'T2'를 도출 된 유형의 'T3'로 제한하는 것을 요구했는데, 다른 방법은 아닙니다. 편집 : 아, 방금 당신의 대답을 편집. 내 의견의 두 번째 부분을 무시하십시오. –

+1

수정 사항을 업데이트해야 할 수도 있습니다. 인터페이스 메서드에서 ''과 그 제약 조건을 재 선언해서는 안됩니다. 나는 이것이 인터페이스 선언의 일부인 ''과 아무런 관계가없는 새로 선언 된 타입이라고 생각한다. –

+0

@ChrisSinclair 당신 말이 맞습니다. 나는 그것을 실현하고 내 대답을 업데이트했습니다. – GolfWolf

5

w0lf의 대답은 직접 솔루션을 제공하는 동안, 나는 몇 가지 배경 설명을주고 싶다.

당신은

class C<A> where A : B 

또는

void F<A>() where A : B 

형태 A : B의 제약 같은 클래스, 인터페이스, 방법 등의 제네릭 형식 매개 변수의 하나로서 A이 있어야 쓸 때 선언되고있다.

콜론 오른쪽에 현재 선언의 제네릭 형식 매개 변수를 배치 했으므로 (건너 뜁니다.) 이 아닌입니다. 이는 일반 형식 매개 변수를 콜론의 왼쪽에있는 외부 선언 (현재 선언이 아닌).

당신이 어떤 선언에 제약 A : B을 형성하려면

A 그 선언에 도입되어야하며 A의 범위는 B의 범위보다 작거나 같아야합니다. 이것이 실용적인 언어 제한 인 이유는 임의의 제네릭 형식 매개 변수 T에 대해 T 형식의 제약 조건에 대한 설명을 T이 소개되는 단일 선언으로 분리하기 때문입니다.

+0

물론, 이해합니다.하지만 당신은 내가 성취하려는 것을 볼 수 있습니다. – CSJ

+0

@CSJ 나는 당신이 성취하려고하는 것을 보았습니다, 아주 분명합니다. 제가 설명하는 것은 언어 제한으로 인해 그렇게하지 못하는 것입니다. 이러한 언어 제한은 본질적으로 제네릭 형식 제약 그래프를 일부 표현 성을 희생하면서 더 쉽게 추론하는 트리로 만듭니다. 이 문제에 대한 해결책으로 w0lf의 제안을 사용할 수 있습니다. –