2010-05-07 24 views
3

Supposons que j'ai une hiérarchie petit héritage des animaux:Est-il possible de faire une approximation de la covariance des génériques en C# <4 dans cette situation hypothétique?

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!"; 
    } 
} 

Ensuite, voici une interface offrant un moyen de transformer strings en IAnimals.

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

Et enfin, voici une stratégie pour le faire:

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; 
    } 
} 

Maintenant, la question. Est-il possible de remplacer les sections marquées [1], [2], et [3] de telle sorte que ce programme compilera et fonctionnera correctement? Si vous ne pouvez pas le faire sans toucher à des parties autres que [1], [2] et [3], pouvez-vous toujours obtenir un IAnimal sur chaque instance d'un Transmogrifier dans une collection contenant des implémentations arbitraires d'un IAnimal? Pouvez-vous même former une telle collection pour commencer?

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"); 
     } 
    } 
} 

Répondre

3

Vous ne pouvez pas faire cela, car il n'y a pas de relation de type entre Transmorgifier<Ape> et Transmorgifier<Bat> de sorte que vous ne pouvez pas les mettre dans la même liste générique (sauf List<object>). La solution évidente est juste pour ITransmorgifier non générique:

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

Ensuite, vous pourriez avoir

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

Je m'en doutais autant. J'espérais qu'il y aurait une supercherie que je pourrais faire avec '.Cast ', mais je suppose que non. –

4

Lee est correct.

Comme vous le laissez entendre par votre question, vous pouvez le faire en C# 4 en marquant ITransmogrifier comme covariant (« out ») en T. Vous pouvez alors faire une List<ITransmogrifier<IAnimal>> et mettre un Transmogrifier<Bat> dans cette liste.

+0

En effet, j'utilise 'in' /' out' avec un abandon insouciant et jubilatoire dans C# 4. Immensément utile. –