c#中的类铸造
本文关键字: | 更新日期: 2023-09-27 17:58:04
这是c#代码
class A {
public int Foo(){ return 5;}
public virtual int Bar(){return 5;}
}
class B : A{
public new int Foo() { return 1;} //shadow
public override int Bar() {return 1;} //override
}
输出
Console.WriteLine(((A)clB).Foo()); // output 5 <<<--
Console.WriteLine(((A)clB).Bar()); // output 1
我们如何得到这个输出。有人能在这里解释一下选班的过程吗。
更新:
这如何显示阴影和覆盖之间的差异
我假设
var clB = new B();
Foo
和Bar
方法的区别在于,虽然Bar
使用继承和多态性来决定调用什么实现,但Foo
方法隐藏了它的原始实现。
总之,A.Foo()
和B.Foo()
是完全不相关的,它们只是碰巧同名。当编译器看到类型为A
的变量调用Foo
时,它会进入并执行A.Foo()
,因为该方法不是虚拟的,所以它不能被覆盖。类似地,当它看到B
类型的变量调用Foo
时,它执行B.Foo()
,而不管变量中包含的实例的实际类型如何。
另一方面,Bar
方法被定义为虚拟的,继承类可以(并且期望)覆盖它的实现。因此,无论何时对Bar
进行调用,无论它是来自声明为A
还是B
的变量,都必须在调用对象本身的层次结构中找到实际调用的方法作为"最新"实现,而不受用于引用对象的变量类型的影响。
在类B
中,您引入了一个new
方法Foo
,该方法与现有方法(继承自A
)具有相同的名称和签名。所以B
有两个同名的方法。如果你能避免的话,你不会这么做。
调用的两个方法Foo
中的哪一个取决于所用变量或表达式(类型为A
或B
)的编译时类型。
相反,方法Bar
是virtual
。B
中只有一种方法Bar
。无论表达式的编译时类型是什么,调用的始终是"正确"的重写。
写入
((A)clB).Foo()
就像说"把clB
当作A
(如果可以的话),然后给我Foo()
的结果"。由于A
具有非虚拟Foo
方法,因此它执行A.Foo
。由于B
的Foo
方法是"new
"方法,因此在本例中不使用它。
写入
((A)clB).Bar()
类似-"把clB
当作A
对待(如果可以的话),然后给我Bar()
的结果"。现在A
有一个虚拟Bar
方法,这意味着它可以在基类中被覆盖。由于对象实际上是一个B
,它具有Foo()
的override
,因此调用B.Foo()
。
var clB = new B();
//Uses B's Foo method
Console.WriteLine(clB.Foo()); // output 1
//Uses A's Foo method since new was use to overload method
Console.WriteLine(((A)clB).Foo()); // output 5
//Uses B's Bar Method
Console.WriteLine(clB.Bar()); // output 1
//Uses B's Bar Method since A's Bar method was virtual
Console.WriteLine(((A)clB).Bar()); // output 1