5

Sorry for the long question but I'm kinda new to C# (I used to use VB.Net)

I fully understand the difference between Overriding and Overloading in both VB.Net and C#.. so there's no problem with the overriding.

Now, in VB.Net there's a difference between Shadowing (using the keyword Shadows) and Overloading (using the keyword Overloads 'with the same arguments') as follows:

  • When using Shadows, it shadows every method with the same name -regardless of the arguments- to become one method only (the shadowed method).
  • When using Overloads -with the same arguments-, it overloads (shadows) only the method with the same name and arguments.

Consider this code:

Class A
    Sub MyMethod()
        Console.WriteLine("A.MyMethod")
    End Sub
    Sub MyMethod(ByVal x As Integer)
        Console.WriteLine("A.MyMethod (x)")
    End Sub
    Sub MyMethod2()
        Console.WriteLine("A.MyMethod2")
    End Sub
    Sub MyMethod2(ByVal x As Integer)
        Console.WriteLine("A.MyMethod2 (x)")
    End Sub
End Class

Class B
    Inherits A
    Overloads Sub MyMethod()
        Console.WriteLine("B.MyMethod")
    End Sub
    Shadows Sub MyMethod2()
        Console.WriteLine("B.MyMethod2")
    End Sub
End Class

Then:

Dim obj As New B()
obj.MyMethod()      'B.MyMethod
obj.MyMethod(10)    'A.MyMethod (x)
obj.MyMethod2()     'B.MyMethod2

While:

obj.MyMethod2(10)   'Error, cuz there's only one 'MyMethod2' (and with zero arguments)

So far so good..

BUT, in C# I'm not getting the same difference between Shadowing (using the keyword New) and Overloading (Same name & arguments)!

So, when trying the same code above in C# (using C# syntax of course :D), the following line:

obj.MyMethod2(10);

will return>> 'A.MyMethod2 (x)'

Looks like no difference between Overloading and Shadowing in C#!!

Anyone can explain why this discrepancy exists?

Thank you

  • In C# you would use the keyword **new** instead of Shadows to obtain the same results. – Spell Jan 13 '16 at 14:24
  • In C#, you cannot remove _all_ the "signatures" from the base class like you apparently can in VB.NET. So if the base class has both `public void MyMethod() { }` and `public void MyMethod(int x) { }`, then if you declare in the inheriting class a new member `public new void MyMethod() { }` it will only hide one of the base class signatures. There is no way you can hide both signatures from the base class. In a sense, the `new` of C# corresponds more to `Overloads` in VB.NET. My knowledge of VB.NET in this respect comes from [this thread answer](https://stackoverflow.com/a/4760614/1336654). – Jeppe Stig Nielsen Oct 18 '17 at 08:51

5 Answers5

9

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.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • "Most members are inheritable; a few, like constructors, are not." - What other members are not inheritable? – Luca Cremonesi Jan 13 '16 at 17:28
  • Do you know of any reference which describes in detail the differences in method hiding between C# and VB? – Dave Doknjas Jan 13 '16 at 18:53
  • 1
    @LucaCremonesi: Destructors are not inherited. And explicit interface methods are a little weird, though I would probably count them as inheritable. – Eric Lippert Jan 13 '16 at 19:11
  • @EricLippert "explicit interface methods are a little weird" - That sounds like a blog candidate. – Tergiver Jan 15 '16 at 20:21
3

C# and VB may use the same framework and IL, but they are not the same language or platform. Some features in C# do not exist in VB, and some features in VB do not exist in C#.

In this case, using the New keyword on a method in C# does not do "shadowing". It is used for method hiding.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
2

Check this

In C#, Shadowing means you may entirely replace the item. For instance, you can shadow a field named ToBeShadowed in the parent class and becoming a method ToBeShadowed() in the child class. And in this process, whenever you use parent class, the item would be a field but if you use child class, the item would a method. Thus, shadowing allows you to completely change the nature of an item with the same name.

public class A {
    public int ToBeShadowed; //This is a field in the parent class
}

public class B : A {
    public void ToBeShadowed(){ //this is a method in the child
        //do something
    }
}

The overloading, however is unlike shadowing at all. You cannot overload a field to a method for instance. Every overloading must have the same return, though it may have different input arguments. Thus overloading is like putting more possibilities for the input arguments without changing the nature of the item. But Shadowing can do so.

public class A { //This is overloading
    public int ToBeOverloaded(); //with no input
    public int ToBeOverloaded(int input); //with 1 input, integer
    public int ToBeOverloaded(string input); //with 1 input, string
}
Ian
  • 30,182
  • 19
  • 69
  • 107
  • @lan, thank you for your reply.. I already know that. But I'm here referring to a specific case (Shadowing -or Overloading- a METHOD with the same arguments).. In VB.Net there's a difference while in C# the difference doesn't seem to be there! – 41686d6564 stands w. Palestine Jan 13 '16 at 14:30
  • 1
    @GeniuSBraiN I see, thus you refer to `Method Hiding` actually. – Ian Jan 13 '16 at 14:32
  • @Ian Also in VB using `Shadows` you can change the signature of the member. – shadow Jan 13 '16 at 19:51
0

Overload is when you have a functions with the same name and return type but different parameters in the same class.

Shadowing (Shadows in VB - New in C#) is when you change the signature of an inherited member. Else it's just override. Shadowing might lead to troubles as it breaks inheritance.

New and Shadows does the same thing. It seems that in VB when you want to hide an overloaded member, you have to shadow all the overloads.

Check this code:

Module StartupModule

    Sub Main()
        Dim l1 As Level1 = New Level3
        l1.Print()
        l1.Print(10)

        Console.WriteLine()

        Dim l2 As Level2 = New Level3
        l2.Print()
        l2.Print("20")

        Console.WriteLine()

        Dim l3 As Level3 = New Level3
        l3.Print()
        l3.Print(DateTime.Now)

        Console.ReadLine()
    End Sub


    Public Class Level1
        Public Overloads Sub Print()
            Console.WriteLine("Level1.Print")
        End Sub

        Public Overloads Sub Print(value As Integer)
            Console.WriteLine("Level1.Print(Value)={0}", value)
        End Sub
    End Class

    Public Class Level2
        Inherits Level1

        Public Shadows Sub Print()
            Console.WriteLine("Level2.Print")
        End Sub

        Public Shadows Sub Print(value As String)
            Console.WriteLine("Level2.Print(Value)={0}", value & "1")
        End Sub
    End Class

    Public Class Level3
        Inherits Level2

        Public Shadows Sub Print()
            MyBase.Print()
        End Sub

        Public Shadows Sub Print(value As DateTime)
            Console.WriteLine("Level3.Print(Value)={0}", value)
        End Sub
    End Class

End Module

Also there is something in your code that seems odd and it is not your fault.

Class A
    Sub MyMethod()
        Console.WriteLine("A.MyMethod")
    End Sub
    ...
End Class

Class B
    Inherits A
    Overloads Sub MyMethod()
        Console.WriteLine("B.MyMethod")
    End Sub
    ...
End Class

Although the compiler accepts it the MyMethod is declared as Overloads in Class B but is actual works as Shadows. Check this example:

Module StartupModule

    Sub Main()
        Dim l1 As Level1 = New Level3
        l1.Print()

        Console.WriteLine()

        Dim l2 As Level2 = New Level3
        l2.Print()

        Console.WriteLine()

        Dim l3 As Level3 = New Level3
        l3.Print()

        Console.ReadLine()
    End Sub


    Public Class Level1
        Public Sub Print()
            Console.WriteLine("Level1.Print")
        End Sub
    End Class

    Public Class Level2
        Inherits Level1

        Public Overloads Sub Print()
            Console.WriteLine("Level2.Print")
        End Sub
    End Class

    Public Class Level3
        Inherits Level2

        Public Overloads Sub Print()
            MyBase.Print()
        End Sub
    End Class

End Module

The big difference I think is that, as I wrote in the beginning of my answer, VB compiler cannot Shadow an Overloaded method.

shadow
  • 1,883
  • 1
  • 16
  • 24
-1

In terms of c# method overloading means providing different versions of the same method name by defining different parameters, e.g.:

int MethodA(int x){
  return x++;
}

int MethodA(int x, int y){
  return x+y;
}

Shadowing (in terms of c# method hiding) is something different, it means that changing the function of a method defined in a base class.e.g.

public class Parent{
   public int MethodX(int x){
         return x++;
   }
}

public class Child : Parent{
   public new int MethodX(int x){
         return x+2;
   }
}

Also note that method hiding is not commonly used as it can lead to problems which are not easy to identify.

daryal
  • 14,643
  • 4
  • 38
  • 54