Suppose I have a small inheritance hierarchy of Animals:
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!";
}
}
Next, here's an interface offering a way to turn strings
into IAnimals
.
public interface ITransmogrifier<T> where T : IAnimal {
T Transmogrify(string s);
}
And finally, here's one strategy for doing that:
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;
}
}
Now, the question. Is it possible to replace the sections marked [1], [2], and [3] such that this program wil开发者_如何学编程l compile and run correctly? If you can't do it without touching parts other than [1], [2], and [3], can you still get an IAnimal
out of each instance of a Transmogrifier
in a collection containing arbitrary implementations of an IAnimal? Can you even form such a collection to begin with?
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");
}
}
}
Lee is correct.
As you imply by your question, you can do this in C# 4 by marking ITransmogrifier as covariant ("out") in T. You can then make a List<ITransmogrifier<IAnimal>>
and put a Transmogrifier<Bat>
into that list.
You can't do this, since there is no type relationship between Transmorgifier<Ape>
and Transmorgifier<Bat>
so you can't put them in the same generic list (except List<object>
). The obvious solution is just to make ITransmorgifier
non-generic:
public interface ITransmogrifier
{
IAnimal Transmogrify(string s);
}
Then you could have
var list = new List<ITransmogrifier>() {
new Transmorgifier<Ape>(), new Transmorgifier<Bat>() ...
};
精彩评论