开发者

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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜