When inheriting an inherited class, the new / override behaviour is not what I would expect:
$ 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. Why does the B class’s new modifier take precedence here? What is the use case for that? Especially as it breaks the obvious use case of having C really override A.
Note that the above code was run on Mono 2.10 running on a Debian-derived distro. But I have confirmed the same behaviour using the C# compiler in MS Visual Studio.
The
newmodifier causes member hiding, which breaks the polymorphic relationship in your class hierarchy. TheSayHimethod ofBis treated as distinct (not an override) fromA’s (thus the choice of the word “new” as keyword).C’s method then overridesB’s, notA’s (which remains hidden).Therefore, when you call
SayHion aCinstance through anAreference, the runtime would resolve it against theAtype, not theCtype (within whichSayHiis a “new” method inherited fromB).If, on the other hand, you were to run:
…you would get the expected polymorphic result:
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. For example:
The
Itemproperty of theObjectContainerclass returns a plainobject. However, inStringContainer, this inherited property is hidden to return astringinstead. Thus:The
QuotedStringContainerclass overrides theItemproperty ofStringContainer, inheriting itsstringreturn type; however, it is still hidden from theobject-returningItemproperty ofObjectContainer. If it were not this way, there would be no way of reconciling their disparate return types…