Когда определяются родовые типы?На это можно повлиять? - PullRequest
8 голосов
/ 01 марта 2011

Я играл с дженериками и видел некоторые странные вещи. Надеюсь, у вас, ребята, есть объяснение! Чтобы упростить все, я поместил «проблему» в пример:

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)
        {
            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();
        }
    }
}

Итак, у меня в лаборатории два животных: собака и птица. Когда я «пну» этих животных, они издают звук. Принтер распечатает звук и тип животного. Когда я запускаю программу, она печатает:

Удар птицей: Животное Lab.Animal говорит «Чирикать!»

Пинок собаки: Животное говорит: «Кора, кора! Я тебя укушу! '

Печать кик-пса: Lab.Dog говорит: «Кора, кора! Я тебя укушу! '

Почему первый удар собаки говорит мне, что это тип Lab.Animal? И ... как мне заставить его вернуться Lab.Dog?

Ответы [ 2 ]

6 голосов
/ 01 марта 2011

Первый удар собаки говорит вам, что типом времени компиляции аргумента типа был Lab.Animal.Другими словами, ваш метод Animal.Kick эффективен:

Printer.Print<Animal>(this, Sound);

Аргументы типа не определяются полиморфно - они определяются во время компиляции.Это становится более сложным, когда аргумент типа одного вызова на самом деле является типом параметра вызывающего контекста, но это в основном то же самое.

Чтобы сказать: Lab.Dog,вам нужно получить фактический тип времени выполнения объекта, например, используя

obj.GetType().FullName
3 голосов
/ 01 марта 2011

Обычно, дженерики определяются во время компиляции, но они также функция времени выполнения.В этом случае вы используете вывод обобщенного типа, который использует переменные и т. Д. Для вывода типа.

В методе:

    public void Kick()
    {
        Printer.Print(this, Sound);
    } 

все, что известно о this в этом контексте,что это должно быть Animal, поэтому существует неявный Anmial, то есть Printer.Print<Animal>(this, Sound)

Другие параметры:

  • используйте GetType(), чтобы найти фактический тип объекта
  • используйте dynamic, чтобы отложить разрешение до времени выполнения (примечание; не идеально использование динамического, но оно работает)
...