2016-08-19 2 views
0

저는 C#에서 제네릭으로 조금 어려움을 겪고 있습니다. 이 코드 조각을 고려해일반적인 derrived 유형의 객체를 반환하는 일반 메서드

public interface A {}; 
public interface B : A {}; 
public interface C : A {}; 

public interface IMyInterface<in T> where T : A {}; 

public class FirstImpl<T> : IMyInterface<T> where T : B {}; 
public class SecondImpl<T> : IMyInterface<T> where T : C {}; 

은 지금은 올바른 구현 형태를 취하고 반환 일부 공장에 필요

public IMyInterface<T> Create<T>() where T : A 
{ 
    if(typeof(T) is B) { 
     return new FirstImpl<T>(); 
    } 
    if(typeof(T) is C) { 
     return new SecondImpl<T>(); 
    } 
} 

이 두 가지 수준에서 작동하지 않습니다. 첫 번째는 return 유형입니다. 두 번째는 더 구체적인 유형이 필요하기 때문에 첫 번째 또는 두 번째 구현에 'T'를 전달할 수 없다는 것입니다. 어떤 생각이 어떻게 해결할 수 있습니까?

+0

글쎄, 문제는 기술적으로 당신이'new FirstImpl ();'을 호출 할 때 제네릭 타입 T가 실제로 B 또는 B 파생물이라는 것을 컴파일러에게 확신시킬 수 없다는 것입니다. 흥미 롭 군. 생각할 거리. Lemme 참조하십시오. –

+0

'새로운 '키워드 몇 개를 남겨 두셨습니까? 질문을 이해하는 것만 큼 어렵습니다. 원하는 코드를 컴파일하더라도 컴파일하지 않아도됩니다. 당신은'return new FirstImpl ();'과'return new SecondImpl ();'을 쓰려고 했습니까? –

+0

이제 수정되었습니다. –

답변

1

디자인을 그대로 유지하려는 경우 가장 짧은 방법은 Create<T>() 메서드 (public IMyInterface<T> Create<T>() where T : A , B, C)와 같은 추가 제약 조건을 추가하는 것입니다. 메소드를 완료하기 위해 기본 케이스의 구현이 필요할 수 있습니다.

public IMyInterface<T> Create<T>() where T : A, B, C 
{ 
    if (typeof(T) is B) 
    { 
     return new FirstImpl<T>(); 
    } 
    if (typeof(T) is C) 
    { 
     return new SecondImpl<T>(); 
    } 
    return new DefaultImpl<T>; 
} 
+0

나는이 접근법을 시도 할 것이며, 계속 지켜봐야 할 것이다. 충고에 감사하다! –

+0

쿨! 나는 당신이 디자인을 동일하게 유지하기를 원한다는 전제 하에서 만 대답했다. 만약 당신이 그것을 바꾸기 위해 열렸다면, 이것보다 더 좋은 디자인 친화적 인 해결책을 얻을 수있을 것이다. :) –

+0

두 번째 생각에 실제로 T가 B 또는 C 만 가능할 수도 있기 때문에 가능하지 않은지 잘 모르겠습니다. –

2

당신은 반사 신경 쓰지 않는 경우, 당신은 그렇게 할 수있는 :

public static IMyInterface<T> Create<T>() where T : A 
{ 
    if (typeof(B).IsAssignableFrom(typeof(T))) 
    { 
     var type = typeof(FirstImpl<>); 
     var boundType = type.MakeGenericType(typeof(T)); 
     return (IMyInterface<T>) Activator.CreateInstance(boundType); 
    } 
    else if(typeof(C).IsAssignableFrom(typeof(T))) 
    { 
     var type = typeof(SecondImpl<>); 
     var boundType = type.MakeGenericType(typeof(T)); 
     return (IMyInterface<T>) Activator.CreateInstance(boundType); 
    } 

    throw new ArgumentException("unknown type " + typeof(T).Name); 
} 

당신은 제네릭 형식을 사용하여 .net fiddle

+0

반사가 좋습니다. 내가 이걸 해 볼까. –

+0

var type = typeof (FirstImpl <>) 그리고 "<>"로 들어가는 것은 무엇입니까? –

+0

typeof (FirstImpl <>)는 언 바운드 형식을 나타냅니다. 내가 추가 한 .net 바이올린을 확인할 수 있습니다. – Nico

3

당신이 코드를 가지고 때마다 그것을 시도하거나 수 메서드를 호출하고 해당 코드가 제네릭 형식 매개 변수에 대한 테스트를 수행하면 잘못 처리하는 것입니다. (그리고 IMHO에 대한 언급은 그다지 심각하지 않습니다.) 제네릭 형식의 요점은 이 아닌 코드를 쓰는 것입니다.은 제네릭 형식에 의존합니다.

static IMyInterface<T> CreateB<T>() where T : B 
{ 
    return new FirstImpl<T>(); 
} 

static IMyInterface<T> CreateC<T>() where T : C 
{ 
    return new SecondImpl<T>(); 
} 

즉 : 당신의 예에서

는 더 나은 방법은 다음과 같이 될 것이다 각 시나리오를 처리 할 수있는 다양한 메소드를 작성하십시오. 호출자는 제약 기반 접근 방식이 작동하려면 이미 처리중인 내용을 알고 있어야합니다. 따라서 적절한 메소드와 각각의 상황에서 사용되는 각각 다른 메소드 이름을 갖는 것은 문제가 아닙니다.

위 시나리오가 사용자의 특정 시나리오를 해결하지 못하는 경우 사용하려는 제네릭 유형뿐만 아니라 사용되는 컨텍스트를 나타내는 좋은 Minimal, Complete, and Verifiable code example이 포함되도록 질문을 개선하십시오.

+0

당신이 말하는 것은 완벽한 의미입니다. 나는 그것을 고려할 것이다. 더 많은 코드 샘플을 개선 할 필요가 없습니다. (모든 타입은 꽤 간단합니다 ... 저는 실험적인 프레임 워크를 만들고 있습니다. 우리는 모든 것을 매개 변수 화하려고하는 이유 인 실험을위한 뛰어난 유연성을 원합니다.) –

관련 문제