How to explain this behaviour with Overloaded and Overridden Methods? [duplicate]
Asked Answered
S

3

16

Could anyone be so nice and explain me why this code shows Derived.DoWork(double). I can come up with some explanations for this behaviour, however I want someone to clarify this for me.

using System;

public class Base
{
    public virtual void DoWork(int param) {
        Console.WriteLine("Base.DoWork");
    }
}

public class Derived : Base
{
    public override void DoWork(int param) {
        Console.WriteLine("Derived.DoWork(int)");
    }

    public void DoWork(double param) {
        Console.WriteLine("Derived.DoWork(double)");
    }

    public static void Main() {
        int val = 5;
        Derived d = new Derived();
        d.DoWork(val);
    }
}
Satinet answered 12/5, 2014 at 17:34 Comment(1)
See 7.3 Member lookup First, the set of all accessible (Section 3.5) members named N declared in T and the base types (Section 7.3.1) of T is constructed. Declarations that include an override modifier are excluded from the set. If no members named N exist and are accessible, then the lookup produces no match, and the following steps are not evaluated.Haematopoiesis
N
10

Eric lippert used to say always "Closer is better".

A method first declared in a derived class is closer than a method first declared in a base class.

So from the above link, derived class is closer hence that is chosen.

This behavior is carefully implemented to avoid Brittle base class problem

For completeness I'll share the bullets:

  • A method first declared in a derived class is closer than a method first declared in a base class.

  • A method in a nested class is closer than a method in a containing class.

  • Any method of the receiving type is closer than any extension method.

  • An extension method found in a class in a nested namespace is closer than an extension method found in a class in an outer namespace.

  • An extension method found in a class in the current namespace is closer than an extension method found in a class in a namespace mentioned by a using directive.

  • An extension method found in a class in a namespace mentioned in a using directive where the directive is in a nested namespace is closer than an extension method found in a class in a namespace mentioned in a using directive where the directive is in an outer namespace.

Nevsa answered 12/5, 2014 at 17:44 Comment(8)
That is exactly the answer I was thinking about!Satinet
He is passing an integer into d.DoWork so it should be printing "Derived.DoWork(int)", not "Derived.DoWork(double)".Centrosphere
See also #1451599Catastrophism
I'd still expect a method with an exact method signature match to be closer than an overload on the derived class with a slightly different signature. Live and learn I guess. Now I have to see what VB does...Archer
@Centrosphere Read this carefully A method first declared in a derived class is closer than a method first declared in a base class, actual method is first declared in base class only so I guess it is not closer.Nevsa
@Trisped, although Derived overrides DoWork(int), the compiler still considers this method to belong to Base. DoWork(double) is compatible, as an int is implicitly being cast to double, and is also defined in Derived, so it is "closer". As a proof, if you change in Derived to new public void DoWork(int), you will see that the new keyword tells the compiler to treat DoWork(int) as being now owned by Derived and will match it instead.Dainedainty
@BradleyUffner It works this way to avoid the brittle base class problem. Check out the updated link.Nevsa
I tested it, and in case anyone is curious, VB.NET calls the Integer version. An interesting choice by the different language teams.Archer
C
4

This behavior is defined in the the C# Language Specification, specifically section 7.5.3 "Overload resolution." Here's a link to an older version, otherwise refer to the CSharp Language Specification.docx that you should have locally, e.g., C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC#\Specifications\1033\CSharp Language Specification.docx.

In this case, methods marked override are excluded, thus the double overload is the only valid option (emphasis mine):

Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. For example, the set of candidates for a method invocation does not include methods marked override (§7.4), and methods in a base class are not candidates if any method in a derived class is applicable (§7.6.5.1).

Chaucerian answered 12/5, 2014 at 17:47 Comment(2)
I am curious to if there would be any situations where exactly this behavior will be useful, and exploied on purpose? At least, the C# design team definitely had something in mind. For people familiar with other OOP languages, like Java for instance (including me) this behavior is not transparent and perhaps unfairly seen as unreasonable.Dainedainty
Actually, I found the reason here in Eric Lippert's blog. It is also present in one of the answers of a duplicate StackOverflow question.Dainedainty
J
1

This behavior is apparently by design:

'When choosing an overload, if there are any compatible methods declared in a derived class, all signatures declared in the base class are ignored - even if they're overridden in the same derived class!' http://social.msdn.microsoft.com/Forums/vstudio/en-US/a70b25d4-f310-4d06-9dc2-a453f822f4f3/function-not-getting-called-when-overloading-the-function-of-base-class-in-derived-class-with?forum=csharpgeneral

Jail answered 12/5, 2014 at 17:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.