通用方法问题/错误?

时间:2012-12-21 10:52:58

标签: c# generics

有人能解释一下这个问题吗?

唯一可行的方法是使用CorrectName中的virtual,然后在Derived中使用virtual,而不是new关键字,但是,为什么会发生这种情况?

为什么如果我使用泛型投射它会给我Base值,如果我直接投射它会给我Derived值? ((输出在下面))

谢谢你们,正如我已经说过的那样,我已经有了“解决方案”,但我想理解

    class Base
    {
        public string Name { get; set; }
        public string CorrectName { get { return Name; } }
    }
    class Derived : Base
    {
        public new string CorrectName { get { return "NEW" + Name; } }
    }
    static void Main(string[] args)
    {
        List<Derived> container = new List<Derived>();

        var d = new Derived() { Name = "NameDerived2" };

        container.Add(d);

        Search<Derived>(container);
        Console.ReadLine();
    }

    static void Search<T>(List<T> list) where T : Base
    {
        foreach (var el in list)
        {
            Console.WriteLine("No Cast -->" + el.CorrectName);
            Console.WriteLine("Generic Cast -->" + (el as T).CorrectName);
            Console.WriteLine("Direct Cast -->" + (el as Derived).CorrectName);
        }
    }

输出:

No Cast -->NameDerived2

Generic Cast -->NameDerived2

Direct Cast -->NEWNameDerived2

真理表:

el is Derived == true
el.GetType().Equals(typeof(Derived)) == true
el.GetType().Equals(typeof(T)) == true
el.GetType().Equals(typeof(Base)) == false
typeof(T).Equals(typeof(Base)) == false
typeof(T).Equals(typeof(Derived)) == true

2 个答案:

答案 0 :(得分:4)

如果没有virtual关键字,基类中的方法不会被覆盖,而是被新实现“隐藏”。您还可以使用new中的Derived关键字来强制执行此操作。正如您在通用方法声明中所述,传递给方法的任何T都必须是Base类型,因此每个T都会转换为Base

现在发生的是,当你不使用virtual时,你会失去多态性,这意味着,即使该对象实际上是Derived类型,但是强制转换为Base,调用Base的{​​{1}}实现,而不是 - 正如您所期望的那样 - CorrectName中的新实现。

仅当您将对象明确转换为Derived时才会调用此方法。

此处也对此进行了讨论和描述:virtual keyword in c#

可能有助于您了解虚拟和非虚拟方法之间差异的另一个链接可能是:http://en.wikipedia.org/wiki/Virtual_method_table

答案 1 :(得分:0)

非虚方法在编译时绑定,而不是在运行时绑定。在编译时,所有可以保证的是TBase,因此编译器将属性访问器绑定到BaseCorrectName,这不会在运行时更改。您使用Derived作为类型参数T来调用该方法,但其他人可以使用继承自Base甚至Base的其他类型来调用它。

但是,虚方法将检查实际的运行时类型并调用正确的重写方法。

您发布的“真实表”与此无关,因为所有这些都是在运行时进行评估的。要证明编译器将T评估为Base,请尝试以下操作:

T t = default(T);
object o = t; // works
Base b = t; // works
Derived d = t; // doesn't work