【问题标题】:When are generic types determined? Can it be influenced?泛型类型何时确定?可以影响吗?
【发布时间】:2011-03-01 11:00:37
【问题描述】:

我一直在玩泛型,并且看到了一些奇怪的东西。希望大家给个解释!为了让一切变得更容易,我将“问题”放在一个例子中:

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.Animal 说‘吠,吠!我会咬你的!'

打印踢狗: Lab.Dog 说‘吠,吠!我会咬你的!'

为什么狗的第一脚告诉我它是Lab.Animal 类型? 还有...我怎样才能让它返回Lab.Dog

【问题讨论】:

    标签: .net methods c#-2.0 generics


    【解决方案1】:

    狗的第一脚告诉你类型参数的编译时类型是Lab.Animal。换句话说,您的Animal.Kick 方法有效:

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

    类型参数不是多态确定的——它们是在编译时确定的。当一个调用的类型参数实际上是调用上下文的类型参数时,情况会变得更加复杂,但它本质上是同一类东西。

    要说Lab.Dog,您必须获取对象的实际执行时间类型,例如使用

    obj.GetType().FullName
    

    【讨论】:

    • GetType() 的问题是它与 typeof() 相比相当昂贵。但这不是示例的重点。谢谢你的解释!
    • @Kees:它“昂贵”正是因为它在执行时而不是在编译时有效地做某事 - 但你使用你需要的东西:)(它真的 有那么贵吗?)
    • 是的,我希望泛型能给我正确的类型。我在我的脚本编译器中使用它。基本上我只需要运行时类型的全名来检查脚本是否已经编译并存在。 GetType() 提供的不仅仅是名称:-)。
    【解决方案2】:

    通常,泛型是在编译时确定的,但它们也是运行时特性。在这种情况下,您使用的是泛型类型推断,它使用变量等来推断类型。

    在方法中:

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

    在这种情况下,所有已知的this 必须是Animal,因此存在一个隐含的 Anmial,即Printer.Print&lt;Animal&gt;(this, Sound)

    其他选项:

    • 使用GetType()查找对象的实际类型
    • 使用dynamic 将分辨率推迟到运行时(注意;不是理想使用动态,但它有效)

    【讨论】:

    • 泛型如何成为运行时特性?
    • @Kees 在.Net 中,他们;例如,它们与 c++ 模板非常不同。实际上,您可以在运行时完全声明一个类型,然后在运行时创建该类型的List&lt;T&gt;Activator.CreateInstance(typeof(List&lt;&gt;).MakeGenericType(someType)) 等。这也是为什么您可以在不需要源代码或头文件的情况下使用库中的泛型 - 它是支持泛型的运行时。
    猜你喜欢
    • 2019-11-04
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多