Difference Between Shadowing and Overriding in C#

Difference between shadowing and overriding in C#?

Well inheritance...

suppose you have this classes:

class A {
public int Foo(){ return 5;}
public virtual int Bar(){return 5;}
}
class B : A{
public new int Foo() { return 1;} //shadow
public override int Bar() {return 1;} //override
}

then when you call this:

A clA = new A();
B clB = new B();

Console.WriteLine(clA.Foo()); // output 5
Console.WriteLine(clA.Bar()); // output 5
Console.WriteLine(clB.Foo()); // output 1
Console.WriteLine(clB.Bar()); // output 1

//now let's cast B to an A class
Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- shadow
Console.WriteLine(((A)clB).Bar()); // output 1

Suppose you have a base class and you use the base class in all your code instead of the inherited classes, and you use shadow, it will return the values the base class returns instead of following the inheritance tree of the real type of the object.

Run code here

Hope I'm making sense :)

C# vs VB.Net, what's the difference between Shadowing and [Overloading (without changing the arguments)]

This is a bit of a confusing question. Let me break it down into smaller questions.

What is inheritance?

When one type inherits from another, the inheritable members of the base type are also members of the derived type. Most members are inheritable; a few, like constructors, are not.

All members? Even private ones?

Yes. Private members are inherited. It may not be legal to look them up by name, but they are still inherited.

In C#, what is overloading a method?

A method is overloaded when there are two methods of the same name but different signatures in one type. (For the purposes of this discussion, the signature of a method consists of its name, generic arity, number of parameters, and parameter types.)

If we have a type D that has two members, M(X) and M(Y), that are overloaded, it is perfectly fine for one of them to be inherited from a base type B, and the other declared in D. They are still overloads.

In C#, how are overloads resolved?

The process is complex, but the basic rules are: first a collection of all accessible methods of the given name is assembled. Then all methods where the signatures do not match the given arguments are removed. The remaining methods are the applicable methods.

Then the methods that are declared in the most derived type are identified and kept; the rest of the applicable methods are removed. (Overridden methods are considered to be methods of the type which originally declared the method, not the type which overrode them.)

If one method remains, it wins. Otherwise, every pair of applicable methods is evaluated to see whether one is better than the other at matching the arguments; any method that is worse than another is eliminated. If this process produces a unique best method then it wins.

There are many more rules involving generic methods and tiebreakers that are not relevant to this discussion.

In C#, what is hiding by name for methods?

If you have a method M(X) in the base class that is inherited by the derived class, the derived class may declare another member of the same signature. This member hides the member in the base class.

In particular, if the hiding method is an applicable method then overload resolution will choose the hiding method over any base type member because, as we already know, overload resolution discards members that were not in the most derived type. Since a hiding method is always in a more derived type than the hidden method, it always wins -- provided it is accessible of course.

In C# how do we mark a member as hiding by name?

You are not required to do anything; simply declaring the member hides the base class member. However, the C# compiler will warn you that the hiding might be unintentional; it often is. You can make the warning go away by using the new keyword on the hiding member. This is the best practice when you intend to hide a member.

In C#, what happens if overload resolution cannot pick a hiding method because it is inapplicable or inaccessible?

Then the usual rules of overload resolution apply. The hiding method is not applicable, so it is removed from the set of methods under consideration immediately. This could mean that no methods declared in the derived type are applicable, and therefore members of the base class might be the applicable methods declared in the most derived type.

Is the rule for how member shadowing works in VB slightly different than the hiding rules in C#?

Yes.

Why?

C# and VB, though deliberately similar, are not different costumes on the same actor. They're different languages with different histories, different design considerations, and different design teams. You should expect small differences like this.

So what is the difference between hiding a method and overloading a method in C#?

Both declare a new member. Adding a new overload adds a method with a different signature, and the methods might or might not be declared in the same type. Hiding a method adds a new method that exactly matches the signature of a method in a base type.

Exact difference between overriding and hiding

Take a look at this answer to a different question by Eric Lippert.

To paraphrase (to the limits of my comprehension), these methods go into "slots". A has two slots: one for Test1 and one for Test2.

Since A.Test1 is marked as virtual and B.Test1 is marked as override, B's implementation of Test1 does not create its own slot but overwrites A's implementation. Whether you treat an instance of B as a B or cast it to an A, the same implementation is in that slot, so you always get the result of B.Test1.

By contrast, since B.Test2 is marked new, it creates its own new slot. (As it would if it wasn't marked new but was given a different name.) A's implementation of Test2 is still "there" in its own slot; it's been hidden rather than overwritten. If you treat an instance of B as a B, you get B.Test2; if you cast it to an A, you can't see the new slot, and A.Test2 gets called.

What is the difference between method hiding and shadowing in C#?


What is the difference between method hiding and shadowing in C#?

Shadowing is another commonly used term for hiding. The C# specification only uses "hiding" but either is acceptable.

You call out just "method hiding" but there are forms of hiding other than method hiding. For example:

namespace N
{
class D {}
class C
{
class N
{
class D
{
N.D nd; // Which N.D does this refer to?

the nested class N hides the namespace N when inside D.

Can we call them as polymorphism (compile time or run time)?

Method hiding can be used for polymorphism, yes. You can even mix method hiding with method overriding; it is legal to introduce a new virtual method by hiding an old virtual method; in that case which virtual method is chosen depends on the compile-time and run-time type of the receiver. Doing that is very confusing and you should avoid it if possible.

Should I shadow or override?

Overloading is an entirely different concept. In essence, overloading allows you to have multiple Add() and Remove() methods while overriding a method 'replaces' the original behavior. Shadowing is somewhere in between. Shadowing 'hides' the original behavior, but you can still access the base method by casting to the base type.

Generally speaking, you don't shadow a member if you can instead override it. Unless you have a very specific reason to do so.

Note that you can't both override and shadow the same member. But you can, for example, both override and overload the original Add() method.

EDIT

You can't override the Add() method, but you can override OnAddingNew(). Similarly, you can't override Remove(), but you can override RemoveItem(). I don't know the specifics for this class, but I suspect that Remove() uses RemoveItem() under the covers.

Your implementation could look somewhat like this:

Imports System.ComponentModel
Imports System.Collections.ObjectModel

Public Class DeviceUnderTestBindingList
Inherits BindingList(Of DeviceUnderTest)

Private Sub New()
MyBase.New()
End Sub

#Region "Add()"

Protected Overrides Sub OnAddingNew(e As AddingNewEventArgs)
Dim newDevice As DeviceUnderTest = DirectCast(e.NewObject, DeviceUnderTest)

Try
If (Not IsValidEntry(newDevice)) Then ' don't add the device to the list
Exit Sub
End If

' (optionally) run additional code
DoSomethingWith(newDevice)
Finally
MyBase.OnAddingNew(e)
End Try
End Sub

Private Function IsValidEntry(device As DeviceUnderTest) As Boolean
' determine whether the specified device should be added to the list
Return True Or False
End Function

Private Sub DoSomethingWith(newDevice As DeviceUnderTest)
' This is where you run additional code that you would otherwise put in the 'Add()' method.
Throw New NotImplementedException
End Sub

#End Region ' Add()

#Region "Remove()"

Public Shadows Function Remove(device As DeviceUnderTest) As Boolean
Try
RemoveItem(IndexOf(device))
Catch
Return False
End Try
Return True
End Function

Protected Overrides Sub RemoveItem(index As Integer)
MyBase.RemoveItem(index)
End Sub

#End Region ' Remove()

End Class

Overriding vs method hiding

Consider:

public class BaseClass
{
public void WriteNum()
{
Console.WriteLine(12);
}
public virtual void WriteStr()
{
Console.WriteLine("abc");
}
}

public class DerivedClass : BaseClass
{
public new void WriteNum()
{
Console.WriteLine(42);
}
public override void WriteStr()
{
Console.WriteLine("xyz");
}
}
/* ... */
BaseClass isReallyBase = new BaseClass();
BaseClass isReallyDerived = new DerivedClass();
DerivedClass isClearlyDerived = new DerivedClass();

isReallyBase.WriteNum(); // writes 12
isReallyBase.WriteStr(); // writes abc
isReallyDerived.WriteNum(); // writes 12
isReallyDerived.WriteStr(); // writes xyz
isClearlyDerived.WriteNum(); // writes 42
isClearlyDerived.writeStr(); // writes xyz

Overriding is the classic OO way in which a derived class can have more specific behaviour than a base class (in some languages you've no choice but to do so). When a virtual method is called on an object, then the most derived version of the method is called. Hence even though we are dealing with isReallyDerived as a BaseClass then functionality defined in DerivedClass is used.

Hiding means that we have a completely different method. When we call WriteNum() on isReallyDerived then there's no way of knowing that there is a different WriteNum() on DerivedClass so it isn't called. It can only be called when we are dealing with the object as a DerivedClass.

Most of the time hiding is bad. Generally, either you should have a method as virtual if its likely to be changed in a derived class, and override it in the derived class. There are however two things it is useful for:

  1. Forward compatibility. If DerivedClass had a DoStuff() method, and then later on BaseClass was changed to add a DoStuff() method, (remember that they may be written by different people and exist in different assemblies) then a ban on member hiding would have suddenly made DerivedClass buggy without it changing. Also, if the new DoStuff() on BaseClass was virtual, then automatically making that on DerivedClass an override of it could lead to the pre-existing method being called when it shouldn't. Hence it's good that hiding is the default (we use new to make it clear we definitely want to hide, but leaving it out hides and emits a warning on compilation).

  2. Poor-man's covariance. Consider a Clone() method on BaseClass that returns a new BaseClass that's a copy of that created. In the override on DerivedClass this will create a DerivedClass but return it as a BaseClass, which isn't as useful. What we could do is to have a virtual protected CreateClone() that is overridden. In BaseClass we have a Clone() that returns the result of this - and all is well - in DerivedClass we hide this with a new Clone() that returns a DerivedClass. Calling Clone() on BaseClass will always return a BaseClass reference, which will be a BaseClass value or a DerivedClass value as appropriate. Calling Clone() on DerivedClass will return a DerivedClass value, which is what we'd want in that context. There are other variants of this principle, however it should be noted that they are all pretty rare.

An important thing to note with the second case, is that we've used hiding precisely to remove surprises to the calling code, as the person using DerivedClass might reasonably expect its Clone() to return a DerivedClass. The results of any of the ways it could be called are kept consistent with each other. Most cases of hiding risk introducing surprises, which is why they are generally frowned upon. This one is justified precisely because it solves the very problem that hiding often introduces.

In all, hiding is sometimes necessary, infrequently useful, but generally bad, so be very wary of it.



Related Topics



Leave a reply



Submit