简体   繁体   English

这种继承特性的用例是什么?

[英]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类重写StringContainerItem属性,继承其string返回类型; however, it is still hidden from the object -returning Item property of ObjectContainer . 但是,它仍然隐藏在ObjectContainerobject -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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM