当我调用下面的代码行时,它会从ClassB执行Get()。
该对象创建为ClassC
,作为new
关键字的方法。理想情况下,它应该从Get()
拨打ClassC
。
Main()
{
ClassA obj = new ClassC();
lbl.Text = obj.Get();
}
public class ClassA
{
public virtual string Get()
{
return "from A";
}
}
public class ClassB : ClassA
{
public override string Get()
{
return "from B";
}
}
public class ClassC : ClassB
{
public new string Get()
{
return "from C";
}
}
任何人都可以帮我找到原因。
答案 0 :(得分:3)
关键是new
中的ClassC
关键字。如果对象被处理为ClassC
,则编译器使用它来掩盖原始的Get()
函数。
如果对象是ClassA
引用,则Get()
将作为原始Get()
处理,从而导致Get()
中的覆盖ClassB
。
答案 1 :(得分:1)
ClassC.Get
具有不同的签名(新字符串)和缺少覆盖,因此它不会覆盖ClassA.Get
。
答案 2 :(得分:1)
魔术被称为虚拟派遣。
ClassB
会覆盖ClassA
Get
,这意味着系统知道ClassA
的下属具有不同的Get
实现。在Get
类型的引用上调用ClassA
时,它将检查引用是否实际为ClassB
或后代,并执行该代码。
当然,这是(kinda-sorta)递归,所以如果ClassB
有任何超过Get
的下降,那么Get
会被调用,等等...... / p>
此处的问题是,Get
中定义的ClassC
与Get
和ClassA
中提到的ClassB
不一样,而是一个全新的new
方法(因此obj.Get()
关键字)恰好具有相同的名称。
因此,当调用ClassC
时,系统不会达到ClassB
,但只能达到ClassC.Get()
并执行该操作。如果您希望new
被执行,可以将override
更改为ClassC
,或尝试通过((ClassC)obj).Get()
引用进行调用,例如{{1}} }
答案 3 :(得分:0)
如果您不首先将其强制转换为ClassA,它将仅从ClassC调用Get()。 Get()的最后一个虚拟实现是来自ClassB的Get(),当你从A调用虚拟Get()方法时会调用它。
答案 4 :(得分:0)
new
关键字隐藏了继承的方法。但是,仅当对象的编译时类型为ClassC
类型时才会这样做。在您的情况下,编译时类型为ClassA
,这导致使用继承的版本。
这就是为什么在使用new
关键字隐藏继承成员之前应该长时间思考的原因之一。根据持有实例的变量的声明类型,可以调用不同的方法:
ClassA a = new ClassC();
ClassC c = (ClassC)a; // Note, this is the SAME instance as in a
Assert.AreSame(a, c);
Console.WriteLine(a.Get()); // prints "from B"
Console.WriteLine(c.Get()); // prints "from C"
答案 5 :(得分:0)
此上下文中的new
关键字是一个隐藏..
这通常在您的基类具有虚拟方法并且您希望与基类虚拟方法名称具有相同名称而不覆盖它时使用强>
如果在派生类中声明此类方法而不覆盖基类方法和new关键字,编译器将生成警告
如果您不使用new
修饰符,编译器将生成警告。
new modifier对编译器说复制成员不是意外,因此编译器不显示警告
答案 6 :(得分:0)
您可以先查看Versioning with override and new。 ClassA
引用将处理原始类中的Get()
。由于此类型已覆盖,因此将调用ClassB
的Get()。
ClassC
引用会将Get()
作为新方法处理,因此ClassC
中的方法将被调用
static void Main(string[] args)
{
ClassA obj = new ClassC();
Console.WriteLine(obj.Get()); // will print out "from B"
ClassC obj2 = new ClassC();
Console.WriteLine(obj2.Get()); // will print out "from C"
}