2014-02-08 1 views
1

공장에서 실험을하면서 컴파일 오류가 발생했습니다. 실제 코드에서는 DI 시스템을 사용하기 때문에 실제로 사용할 팩토리 구현은 아닙니다. 나는 이것이 내가 도움을 구하지 않는 것이기 때문에 이것을 앞에서 언급하고 싶었다.오류 : "유형을 제네릭 유형의 메소드에서 유형 매개 변수로 사용할 수 없습니다." 제약이나 주조로 해결할 수 있습니까?

아래 스 니펫과 혼동 스럽다면 여러 유형을 반환 할 수 있도록 Create() 메소드를 제한하는 방법이 있습니다. 컴파일러 오류는 다음과 같습니다

public static class UniversalFactory 
{ 
    // New factories should be added here. 
    private static readonly IFactory<IFoo> FooFactoryEx; 
    private static readonly IFactory<IBar> BarFactoryEx; 

    static UniversalFactory() 
    { 
     // These bindings could also be provided via a DI framework like Ninject. 
     FooFactoryEx = new FooFactory(); 
     BarFactoryEx = new BarFactory(); 
    } 

    // Maps concrete objects to factories according to the interface(s) they implement. 
    public static TConcreteType Create<TConcreteType>(int id) 
    { 
     if (typeof(TConcreteType).IsAssignableFrom(typeof(IFoo))) 
      return FooFactoryEx.Create<TConcreteType>(id); 
     if (typeof(TConcreteType).IsAssignableFrom(typeof(IBar))) 
      return BarFactoryEx.Create<TConcreteType>(id); 
     return default(TConcreteType); 
    } 
} 

같은 위의 외모에 대한 테스트 코드는 :

public class TestClass 
{ 
    public void TestMain() 
    { 
     var foo1 = UniversalFactory.Create<FooImpl>(1); 
     var foo2 = UniversalFactory.Create<FooImpl>(2); 
     var bar1 = UniversalFactory.Create<BarImpl>(1); 
    } 
} 

오류가 될 것으로 보인다 여기

The type 'TConcreteType' cannot be used as type parameter 'TConcreteType' 
in the generic type or method 'Tests.IFactory<TFactoryType>.Create<TConcreteType>(int)'. 
There is no boxing conversion or type parameter conversion from 'TConcreteType' to 
'Tests.IFoo'. 

샘플 코드의 중요한 부분입니다 TConcreteType은 다음 줄에 대해 IFoo로 제한되어야합니다.

return FooFactoryEx.Create<TConcreteType>(id); 

동시에 동안 (엄청나게)이 라인 IBar로 제한 :

return BarFactoryEx.Create<TConcreteType>(id); 

나는 내가 유형 검사를 할 수 있어요 이후이 제약없이 작동 할 것으로 예상했을 것이다 그러나 같은 :

if (typeof(TConcreteType).IsAssignableFrom(typeof(IFoo))) 

그러나 제한이나 타입 캐스팅으로 인해 상황이 해결되지 않았습니다. 불가능한 일을하려고합니까? 아니면 아직 시도하지 않은 컴파일러 오류에서 암시 된 명백한 제한이 있습니까?

EDIT # 1 : "FooImpl : IFoo"및 "BarImpl : IBar"을 지적해야합니다.

는 는

편집 # 2 : 내 예에서 중요한 형 제약 탈락하기 때문에이 정보는 크리스 마틴 (Chris Martin)이 추가되었다 : 내가 아는 한

public interface IFactory<in TFactoryType> 
{ 
    TConcreteType Create<TConcreteType>(int id) where TConcreteType : TFactoryType; 
} 

답변

1

이 오류의 원인을 이해하는 데 문제가 있으면 컴파일러에서 수행해야하는 작업을 시도해야합니다. 제네릭을 실제 유형으로 대체하십시오.

public static FooImpl Create(int id) 
{ 
    if (typeof(FooImpl).IsAssignableFrom(typeof(IFoo))) 
    //"where FooImpl : IFoo", returns FooImpl, looks fine 
     return FooFactoryEx.Create<FooImpl>(id); 
    if (typeof(FooImpl).IsAssignableFrom(typeof(IBar))) 
    //"where FooImpl : IBar". Wait... what? 
     return BarFactoryEx.Create<FooImpl>(id); 
    return default(FooImpl); 
} 

훨씬 이해가되지 않습니다 그것을하지 : 여기 TConcreteTypeFooImpl 곳에는 경우 모양을 무엇입니까? 컴파일러는 BarFactoryEx.Create<FooImpl>(id);이 절대로 실행되지 않는다는 것을 알 길이 없습니다. IFactory.Create<T>()에서 유형 제한을 제거하거나 동적 코드 생성에 뛰어 들지 않는 한이를 우회 할 수있는 방법이 없습니다. 일반적으로 나는 원래의 접근 방식이 더 좋았다고 생각합니다. (UniversalFactory.FooFactory.Create())

+0

동의 함. 나는 어제 대화에서이 같은 결론을내는 것을 끝내었다. 어쨌든 모든 아이디어가 실제로 "똑똑한"것이기는하지만 원래의 방식은 약간 "똑똑"하지 않습니다. – jmsb

0

가의 typeof 반환 일부 다른 데이터는 전적으로 해당 유형 어떤 수업이 무엇인지 알려줍니다. 두 개의 typeof는 두 개의 완전히 무관 한 클래스의 타입을 요청하더라도 동일한 데이터 타입을 가져야합니다.

이 작업을 수행하기 위해 필요한 것은 TConcreteType이 IFoo 및 IBar 인터페이스를 구현하는 것입니다.

+0

TConcreteType 사용 모두에 제한되어있는 경우 'TConcrete 유형 여기서 IFoo, IBar'는 다음 두 줄은 IFoo 및 IBar가 서로를 구현하지 않기 때문에 실패하는 것을 계속한다. 이 테스트는 FooImpl과 같은 구체적인 유형을 전달할 수 있는지 여부를 확인하고 메소드를 사용하여 FooImpl이 구현하는 인터페이스를 처리하는 팩토리에 매핑하고 해당 팩토리를 사용하여 생성합니다. 제가하려고 한 것은 불가능한 일입니까, 그렇다면 기술적 인 측면에서, 왜죠? – jmsb

1

확실하지 않습니다. 이것은 잘 작동합니다.

https://gist.github.com/trbngr/8911315

+0

광산에 삽화가 누락 되었기 때문에 OP에 편집을 추가했습니다. Nikita Brizhak도 이것을 잡았다. 내 테스트를 방해하는 유형 안전성에 대한 추가 제한이 있습니다. 오케이. – jmsb

관련 문제