Why are these two methods not ambiguous? Why are these two methods not ambiguous? asp.net asp.net

Why are these two methods not ambiguous?


Jon Skeet answered a similar question (without the inheritance complication) here:

When the compiler has two otherwise-equal options to choose from, it will use an overload which doesn't need use any unsupplied optional parameters in preference to one that does...

In your case, however, the method from the RestController is being chosen because it's the more derived class. Jon does a good job of addressing the topic in detail in his book C# in Depth -- look at the inheritance section of that page, which essentially states that the compiler will prefer a method on the actual instance class before methods on less derived classes.


EDIT:

I am leaving my original answer for posterity because I think it lets you visualize things, but DO NOT BE CONFUSED! The compiler does not actually treat the optional parameter as syntactic sugar for an overridden method. It treats it as a single method with an optional parameter. Dusty's answer, mentioning that "the method from the RestController is being chosen because it's the more derived class," is correct.

ORIGINAL (With visible edits for correctness):

Because they are NOT ambiguous. In order to be ambiguous the methods need to have the same signature. The fact that the string message parameter has a default value of null effectively creates BEHAVES as though it creates two callable overrides, one of which HIDES the original method, and one of which is distinctly callable with a string.

You are effectively doing creating the same behavior as if you were to do this:

public class RestController : ApiController{    protected new OkResult Ok()    {        return Ok(null);    }    protected OkResult Ok(string message)    {        // Do your thing...    }}

You will find there is no way to directly call ApiController.Ok() from PersistenceRestController.

If you want to call ApiController.Ok() from RestController, you'll have to use the base keywoard: base.Ok();


While @DimitarTsonev and @Dusty are telling true stuffs, but your answer is something between their answers. Here, you have inheritance situation. See these classes:

public class Foo {    public void Bar() {    }}public class Foo2 : Foo{    public void Bar(string message = null) {    }}public class Foo3 : Foo2{    public void Test(){        Bar();    }}

When you call Bar() in your Foo3 class, the runtime will lookup after the method inside the Foo3 class. If found it, execute it, otherwise go to the top class: Foo2 and look after Bar method. Is there any? yes! so execute it! that's why when you call Ok, your RestControllers' version get executed.

But also, the Foo2.Bar(string message = null) will not conflict with Foo.Bar() because they are NOT ambiguous as @DimitarTsonev said. So, your code will work just fine.

AND, what about calling Foo.Bar() from Foo3? You have to use casting here:

public class Foo3 : Foo2 {    public void Test() {        Bar(); // this will execute Foo2.Bar()    }    public void Test2() {        ((Foo)this).Bar(); // this one will execute Foo.Bar()    }}