This is the signature for the Ok()
method in ApiController
:
protected internal virtual OkResult Ok();
And this is my method from my RestController
class (which extends from ApiController
):
// Note that I'm not overriding base method
protected IHttpActionResult Ok(string message = null);
Since OkResult
implements IHttpActionResult
, both of these methods can be called like this:
IHttpActionResult result = Ok();
In fact, that's what I'm doing in my application.
My class PersistenceRestController
(which extends from RestController
), has these lines of code:
protected override async Task<IHttpActionResult> Delete(Key id)
{
bool deleted = //... Attempts to delete entity
if(deleted) return Ok();
else return NotFound();
}
This compiles fine, and no warning is raised about method ambiguity. Why is that?
PersistenceRestController
has also inherited the protected methods from ApiController
so it should have both versions of Ok()
(and it does).
At execution, the method executed is the one from my RestController
.
How does the compiler know which method to run?
This ambiguous method call error always comes with method overloading where compiler fails to find out which of the overloaded method should be used. Suppose we have a java program like below.
The declaration of a member with an ambiguous name in a derived class is not an error. The ambiguity is only flagged as an error if you use the ambiguous member name. For example, suppose that two classes named A and B both have a member named x , and a class named C inherits from both A and B .
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With