2010-05-07 4 views
3

은 가정하자 나는 동물의 작은 상속 계층 구조가 있습니다이 가상 상황에서 C# <4의 제네릭 공분산을 끝내기가 가능합니까?

public interface IAnimal { 
    string Speak(); 
} 

public class Animal : IAnimal { 
    public Animal() {} 
    public string Speak() { 
     return "[Animal] Growl!"; 
    } 
} 

public class Ape : IAnimal { 
    public string Speak() { 
     return "[Ape] Rawrrrrrrr!"; 
    } 
} 

public class Bat : IAnimal { 
    public string Speak() { 
     return "[Bat] Screeeeeee!"; 
    } 
} 

다음, 여기 IAnimalsstrings을 설정하는 방법을 제공하는 인터페이스입니다.

public class Transmogrifier<T> : ITransmogrifier<T> where T : IAnimal, new() { 
    public T Transmogrify(string s) { 
     T t = default(T); 
     if (typeof(T).Name == s) 
      t = new T(); 
     return t; 
    } 
} 

이제 질문 :

public interface ITransmogrifier<T> where T : IAnimal { 
    T Transmogrify(string s); 
} 

는 그리고 마지막으로, 여기에 작업을 수행하기위한 하나 개의 전략이다. [1], [2] 및 [3]으로 표시된 섹션을 바꿀 수 있습니까? 그러면이 프로그램이 올바르게 컴파일되고 실행됩니다. [1], [2], [3] 이외의 부분을 건드릴 수 없다면 Transmogrifier의 각 인스턴스에서 여전히 IAnimal을 가져올 수 있으며 IAnimal의 임의의 구현을 포함하는 컬렉션에 있습니까? 그런 컬렉션을 시작할 수 있습니까? Transmorgifier<Ape>Transmorgifier<Bat> 사이에 형의 관계가 그래서 당신은 (List<object> 제외) 같은 일반적인 목록에 넣을 수 없기 때문에

static void Main(string[] args) { 
     var t = new Transmogrifier<Ape>(); 
     Ape a = t.Transmogrify("Ape"); 
     Console.WriteLine(a.Speak()); // Works! 

     // But can we make an arbitrary collection of such animals? 
     var list = new List<Transmogrifier<[1]>>() { 
      // [2] 
     }; 

     // And how about we call Transmogrify() on each one? 
     foreach (/* [3] */ transmogrifier in list) { 
      IAnimal ia = transmogrifier.Transmogrify("Bat"); 
     } 
    } 
} 

답변

3

당신은이 작업을 수행 할 수 없습니다. 확실한 솔루션은 ITransmorgifier는 제네릭이 아닌 수 있도록하는 것입니다 :

public interface ITransmogrifier 
{ 
    IAnimal Transmogrify(string s); 
} 

는 그런 다음

var list = new List<ITransmogrifier>() { 
    new Transmorgifier<Ape>(), new Transmorgifier<Bat>() ... 
}; 
+0

나는 그다지 의심 스럽습니다. 나는 .Cast '으로 할 수있는 몇 가지 속임수가 있기를 바랐지만, 나는 그렇지 않을 것이라고 생각한다. –

4

리가 올바른지있을 수 있습니다.

귀하의 질문에 암시하는 바와 같이, T에서 ITransmogrifier를 공변 ("out")으로 표시하여 C# 4에서이 작업을 수행 할 수 있습니다. 그러면 List<ITransmogrifier<IAnimal>>을 만들고 Transmogrifier<Bat>을 해당 목록에 넣을 수 있습니다.

+0

사실, 나는 C# 4에서 무모하고 기쁜 포기로'in/out '을 사용하고 있습니다. 매우 유용합니다. –

관련 문제