The new
modifier causes member hiding, which breaks the polymorphic relationship in your class hierarchy. The SayHi
method of B
is treated as distinct (not an override) from A
’s (thus the choice of the word “new” as keyword). C
’s method then overrides B
’s, not A
’s (which remains hidden).
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
).
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. 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
. However, in StringContainer
, this inherited property is hidden to return a string
instead. 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; however, it is still hidden from the object
-returning Item
property of ObjectContainer
. 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