When are generic types determined? Can it be influenced?
I've been playing around with generics and I've been seeing some weird stuff. I hope you guys have an explanation! To make everything easier I've put the "problem" into an example:
namespace Lab
{
public class Animal
{
public Animal(string sound)
{
this.Sound = sound;
}
public string Sound { get; private set; }
public void Kick()
{
Printer.Print(this, Sound);
}
}
public class Dog : Animal
{
public Dog() : base("Bark, bark! I'll bite you!") { }
}
public class Printer
{
public static void Print<T>(T obj, string message)
{
开发者_如何学C System.Console.WriteLine("{0} says '{1}' \n", typeof(T).FullName.PadRight(10), message);
}
}
public static class Program
{
static void Main(string[] args)
{
Animal bird = new Animal("Tweet!");
Dog dog = new Dog();
System.Console.WriteLine("Kick bird:");
bird.Kick();
System.Console.WriteLine("Kick dog:");
dog.Kick();
System.Console.WriteLine("Print kick dog:");
Printer.Print(dog, dog.Sound);
System.Console.ReadLine();
}
}
}
So, I have two animals in my Lab: a dog and a bird. When I "kick" those animals they'll make a sound. The printer will print the sound and the type of animal. When I run the program it prints:
Kick bird: Lab.Animal says 'Tweet!'
Kick dog: Lab.Animal says 'Bark, bark! I'll bite you!'
Print kick dog: Lab.Dog says 'Bark, bark! I'll bite you!'
Why does the first kick of the dog tell me it is of the type Lab.Animal
?
And... how can I get it to return Lab.Dog
?
The first kick of the dog tells you that the compile-time type of the type argument was Lab.Animal. In other words, your Animal.Kick
method is effectively:
Printer.Print<Animal>(this, Sound);
Type arguments aren't determined polymorphically - they're determined at compile-time. It becomes more complicated when the type argument of one call is actually the type parameter of the calling context, but it's fundamentally the same kind of thing.
To make it say Lab.Dog
, you'd have to get the actual execution-time type of the object, e.g. using
obj.GetType().FullName
Normally, generics are determined at compile time, but they are also a runtime feature. In this case you are using generic type inference, which uses the variables etc to infer type.
In the method:
public void Kick()
{
Printer.Print(this, Sound);
}
all that is known of this
in this context is that it must be Animal
so there is an implicit Anmial, i.e. Printer.Print<Animal>(this, Sound)
Other options:
- use
GetType()
to find the actual type of the object - use
dynamic
to defer resolution to runtime (note; not an ideal use of dynamic, but it works)
精彩评论