Reputation: 5010
Can anyone explain the actual use of method hiding in C# with a valid example ?
If the method is defined using the new
keyword in the derived class, then it cannot be overridden. Then it is the same as creating a fresh method (other than the one mentioned in the base class) with a different name.
Is there any specific reason to use the new
keyword?
Upvotes: 13
Views: 10908
Reputation: 159
One of the few use cases for it is restricting access modifiers since you can't do it in overridden properties and methods.
In my case I had to use it in order to have a base class, let's call it M, which has many properties that are publicly gettable and settable, and then have a derived, concrete class, called X, that actually has to do stuff and needs to prevent some of those properties from being changed.
Example:
class M
{
public object A { get; set; }
}
class X : M
{
public new object A
{
get => base.A;
private set => base.A = value;
}
}
So, when I'm working with an X
reference, even if the actual object is of type M
, I can't set A on it.
Another thing you may need to do, is to return a different type, most likely a derived type. For example, I could have my X.A
property have a different type.
class X : M
{
public new CustomObject A
{
get => base.A as CustomObject;
private set => base.A = value;
}
}
In other words, my M
class is a simple POCO class, only representing the pure data, useful for things like serialization. My X
class needs to prevent certain things from happening, like setting A
in this case (which by the way is possible by casting the object, but highly unlikely to actually do it by mistake).
Upvotes: 0
Reputation: 355
One time when you would use them is when you need to add/modify an attribute that is on a base-class method. For example:
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler TextChanged
{
add { base.TextChanged += value; }
remove { base.TextChanged -= value; }
}
The base Control
class has a TextChanged
event, but the base event has all kinds of attributes slapped on it to prevent it from showing up in intellisense or the designer. Because the class I used that in makes extensive use of both the Text
property and the TextChanged
event, I wanted the TextChanged
event to show up in intellisense and be visible in the properties window.
Upvotes: 1
Reputation: 49
This might help.
class Base
{
public void F() {}
}
class Derived: Base
{
public void F() {} // Warning, hiding an inherited name
}
In the above example, the declaration of F in Derived causes a warning to be reported. Hiding an inherited name is specifically not an error, since that would preclude separate evolution of base classes. For example, the above situation might have come about because a later version of Base introduced an F method that wasn't present in an earlier version of the class. Had the above situation been an error, then any change made to a base class in a separately versioned class library could potentially cause derived classes to become invalid. Source: https://msdn.microsoft.com/en-us/library/aa691135%28v=vs.71%29.aspx
Upvotes: 0
Reputation: 81153
One slightly obscure scenario where method hiding would be appropriate, but for a lack of any clean idiomatic way of expressing it, is in circumstances where a base class exposes a protected member to an inheritable descendant, but that descendant knows that there is no way any further derived classes could use that member without breaking things. A prime example of a method which many classes should hide (but very few do) is MemberwiseClone()
. In many cases, if a class has a private
member which expects to be the only extant reference to a mutable object, there is no possible means by which a derived class could ever use MemberwiseClone()
correctly.
Note that hiding of protected members does not constitute a violation of the LSP. Conformance with the LSP requires that in places where code might be expecting reference to a base-class object but receives a reference to a derived-class object, the latter object should work as would the base-class one. Protected members, however, are outside the scope of the LSP, since every type knows its base type absolutely. If Bar
and Boz
both derive from Foo
, and Boz
hides a protected member that Bar
requires, the fact that Boz
hides the member won't affect Bar
, because Bar
's base-type instance can't possibly be a Boz
or anything other than Foo
. No substitution is possible, and hence substitutability is irrelevant.
Upvotes: 1
Reputation: 26782
One use I sometimes have for the new keyword is for 'poor mans property covariance' in a parallell inheritance tree. Consider this example:
public interface IDependency
{
}
public interface ConcreteDependency1 : IDependency
{
}
public class Base
{
protected Base(IDependency dependency)
{
MyDependency = dependency;
}
protected IDependency MyDependency {get; private set;}
}
public class Derived1 : Base // Derived1 depends on ConcreteDependency1
{
public Derived1(ConcreteDependency1 dependency) : base(dependency) {}
// the new keyword allows to define a property in the derived class
// that casts the base type to the correct concrete type
private new ConcreteDependency1 MyDependency {get {return (ConcreteDependency1)base.MyDependency;}}
}
The inheritance tree Derived1 : Base has a 'parallell dependency' on ConcreteDependency1 : IDependency'. In the derived class, I know that MyDependency is of type ConcreteDependency1, therefore I can hide the property getter from the base class using the new keyword.
EDIT: see also this blog post by Eric Lippert for a good explanation of the new keyword.
Upvotes: 14
Reputation: 32900
I think ArsenMkrt's example is not fully correct, at least it does not fully explain the hiding feature. By dropping the new keyword from the Foo method in class B, you will still get the output
A::Foo()
B::Foo()
A::Foo()
In a programming language like Java, where all methods are "virtual", you'd expect to get the output
A::Foo()
B::Foo()
B::Foo()
by taking ArsenMkrt's code above, due to the instantiation
A a;
B b;
a = new A();
b = new B();
a.Foo();
b.Foo();
a = new B(); //<< Here
a.Foo();
In his example however, you still get "A::Foo()" because in C# methods aren't virtual by default and so the method B::Foo() automatically hides A's Foo(). To achieve the polymorphic behavior one has to write it as follows instead:
class A
{
public virtual void Foo() { Console.WriteLine("A::Foo()"); }
}
class B : A
{
public override void Foo() { Console.WriteLine("B::Foo()"); }
}
Now is where the "new" keyword comes in. Actually when you leave the "override" from B::Foo(), then you again would hide A::Foo() meaning that you don't override it's default behavior and you don't achieve polymorphism, i.e. you get "A::Foo()" again as output. The same can be achieved - and here's where I don't 100% understand why you HAVE to put it - by placing the "new" keyword like..
class A
{
public virtual void Foo() { Console.WriteLine("A::Foo()"); }
}
class B : A
{
public new void Foo() { Console.WriteLine("B::Foo()"); }
}
and you again get the output
A::Foo()
B::Foo()
A::Foo()
Upvotes: 7
Reputation: 50712
C# not only supports method overriding, but also method hiding. Simply put, if a method is not overriding the derived method, it is hiding it. A hiding method has to be declared using the new keyword. The correct class definition in the second listing is thus:
using System;
namespace Polymorphism
{
class A
{
public void Foo() { Console.WriteLine("A::Foo()"); }
}
class B : A
{
public new void Foo() { Console.WriteLine("B::Foo()"); }
}
class Test
{
static void Main(string[] args)
{
A a;
B b;
a = new A();
b = new B();
a.Foo(); // output --> "A::Foo()"
b.Foo(); // output --> "B::Foo()"
a = new B();
a.Foo(); // output --> "A::Foo()"
}
}
}
Upvotes: 7