有人能解释一下这个问题吗?
唯一可行的方法是使用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
答案 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)
非虚方法在编译时绑定,而不是在运行时绑定。在编译时,所有可以保证的是T
是Base
,因此编译器将属性访问器绑定到Base
版CorrectName
,这不会在运行时更改。您使用Derived
作为类型参数T
来调用该方法,但其他人可以使用继承自Base
甚至Base
的其他类型来调用它。
但是,虚方法将检查实际的运行时类型并调用正确的重写方法。
您发布的“真实表”与此无关,因为所有这些都是在运行时进行评估的。要证明编译器将T
评估为Base
,请尝试以下操作:
T t = default(T);
object o = t; // works
Base b = t; // works
Derived d = t; // doesn't work