[英]What is the use case for this inheritance idiosyncrasy?
When inheriting an inherited class, the new / override behaviour is not what I would expect: 继承继承的类时,new / override行为不是我所期望的:
$ cat Program.cs
using System;
class A {
public virtual void SayHi() {
Console.WriteLine("From A");
}
}
class B : A {
public new virtual void SayHi() {
Console.WriteLine("From B");
}
}
class C : B {
public override void SayHi() {
Console.WriteLine("From C");
}
}
public class Program {
public static void Main() {
A p = new C();
p.SayHi();
}
}
$ ./Program.exe
From A
As class C overrides the sayHi() method I would expect the output to be From C
. 由于C类重写了sayHi()方法,我希望输出为
From C
Why does the B class's new
modifier take precedence here? 为什么B类的
new
修饰符优先于此? What is the use case for that? 那是什么用例? Especially as it breaks the obvious use case of having C really override A.
特别是因为它打破了C真正覆盖A的明显用例。
Note that the above code was run on Mono 2.10 running on a Debian-derived distro. 请注意,上面的代码是在Debian派生的发行版上运行的Mono 2.10上运行的。 But I have confirmed the same behaviour using the C# compiler in MS Visual Studio.
但我已经使用MS Visual Studio中的C#编译器确认了相同的行为。
The new
modifier causes member hiding, which breaks the polymorphic relationship in your class hierarchy. new
修饰符会导致成员隐藏,这会破坏类层次结构中的多态关系。 The SayHi
method of B
is treated as distinct (not an override) from A
's (thus the choice of the word “new” as keyword). 所述
SayHi
的方法B
从视为不同 (不是重写) A
的(因此,‘新’字作为关键字的选择)。 C
's method then overrides B
's, not A
's (which remains hidden). C
的方法然后覆盖B
,而不是A
(它仍然是隐藏的)。
Therefore, when you call SayHi
on a C
instance through an A
reference, the runtime would resolve it against the A
type, not the C
type (within which SayHi
is a “new” method inherited from B
). 因此,当您通过
A
引用在C
实例上调用SayHi
时,运行时将针对A
类型而不是C
类型(其中SayHi
是从B
继承的“新”方法)解析它。
If, on the other hand, you were to run: 另一方面,如果你要跑:
B p = new C();
p.SayHi();
…you would get the expected polymorphic result: ...你会得到预期的多态结果:
From C
Edit : Since you requested a use-case, here's one. 编辑 :由于您请求了一个用例,这里是一个。 Before the introduction of generics in .NET Framework 2.0, member hiding was sometimes used as a means of altering the return types of inherited methods in derived classes (something you can't do when overriding) in order to return more specific types.
在.NET Framework 2.0中引入泛型之前,成员隐藏有时用作更改派生类中的继承方法的返回类型(在覆盖时无法执行的操作)以返回更多特定类型的方法。 For example:
例如:
class ObjectContainer
{
private object item;
public object Item
{
get { return item; }
set { item = value; }
}
}
class StringContainer : ObjectContainer
{
public new virtual string Item
{
get { return base.Item as string; }
set { base.Item = value as string; }
}
}
class QuotedStringContainer : StringContainer
{
public override string Item
{
get { return "\"" + base.Item + "\""; }
}
}
The Item
property of the ObjectContainer
class returns a plain object
. ObjectContainer
类的Item
属性返回一个普通object
。 However, in StringContainer
, this inherited property is hidden to return a string
instead. 但是,在
StringContainer
,隐藏此继承属性以返回string
。 Thus: 从而:
ObjectContainer oc = new StringContainer();
object o = oc.Item; // Valid, since ObjectContainer.Item is resolved
string s1 = oc.Item; // Not valid, since ObjectContainer.Item is still resolved
string s2 = ((StringContainer)oc).Item;
// Valid, since StringContainer.Item is now resolved
The QuotedStringContainer
class overrides the Item
property of StringContainer
, inheriting its string
return type; QuotedStringContainer
类重写StringContainer
的Item
属性,继承其string
返回类型; however, it is still hidden from the object
-returning Item
property of ObjectContainer
. 但是,它仍然隐藏在
ObjectContainer
的object
-returning Item
属性中。 If it were not this way, there would be no way of reconciling their disparate return types… 如果不是这样,就没有办法调和他们不同的回报类型......
ObjectContainer oc = new QuotedStringContainer();
object o = oc.Item; // Valid, since ObjectContainer.Item is resolved
string s1 = oc.Item; // Not valid, since ObjectContainer.Item is still resolved
string s2 = ((StringContainer)oc).Item;
// Valid, since QuotedStringContainer.Item is now resolved
// (polymorphism!)
string s3 = ((QuotedStringContainer)oc).Item;
// Valid, since QuotedStringContainer.Item is now resolved
C
is overriding the shadowed version of the method (which is being shadowed in B
) and not overriding the one in A
. C
正在覆盖方法的阴影版本(在B
被遮蔽 )而不是覆盖A
的阴影版本。
As result, when you are using a variable of type A
, the SayHi
defined in A
is called, as it isn't overridden in C
. 因此,当您使用
A
类型的变量时,将调用A
定义的SayHi
,因为它在C
未被覆盖。
C
overrides B
's method, so when you cast it to A
, you end up calling the virtual defined in A
. C
会覆盖B
的方法,因此当您将其强制转换为A
,最终会调用A
定义的虚拟。
See ECMA 334: C# Language Specification under 17.5.3 is pretty much your example (page 294). 请参阅ECMA 334: 17.5.3下的C#语言规范几乎就是您的示例(第294页)。
因为C类没有覆盖A类中的SayHi方法,所以它覆盖了B中的'new'方法。由于你的转换为A,编译器将其解析为对A.SayHi()而不是C的调用。打招呼()
The last example from this msdn page explains closely to what is happening here. 这个msdn页面的最后一个例子详细解释了这里发生的事情。
Basically the new modifier causes the method in A to be hidden from C, and since it is public when C overrides it overrides the method from B(which is treated as its own distinct method). 基本上,new修饰符会导致A中的方法从C中隐藏,并且因为当C覆盖它时它是公共的,它会覆盖B中的方法(它被视为自己的不同方法)。
If you set the method in B to private, C would again override the method in A. 如果将B中的方法设置为private,则C将再次覆盖A中的方法。
class B : A
{
private new void SayHi()
{
Console.WriteLine("From B");
}
}
Results in: From C
结果:
From C
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.