Seems like in .NET Framework there is an issue with optional parameters when you override the method. The output of the code below is:
“bbb”
“aaa”
. But the output I’m expecting is:
“bbb”
“bbb”
.Is there a solution for this. I know it can be solved with method overloading but wondering the reason for this. Also the code works fine in Mono.
class Program
{
class AAA
{
public virtual void MyMethod(string s = "aaa")
{
Console.WriteLine(s);
}
public virtual void MyMethod2()
{
MyMethod();
}
}
class BBB : AAA
{
public override void MyMethod(string s = "bbb")
{
base.MyMethod(s);
}
public override void MyMethod2()
{
MyMethod();
}
}
static void Main(string[] args)
{
BBB asd = new BBB();
asd.MyMethod();
asd.MyMethod2();
}
}
One thing worth noting here, is that the overridden version is called each time. Change the override to:
And the output is:
A method in a class can do one or two of the following:
It may not do both, as an abstract method does only the former.
Within
BBBthe callMyMethod()calls a method defined inAAA.Because there is an override in
BBB, calling that method results in an implementation inBBBbeing called.Now, the definition in
AAAinforms calling code of two things (well, a few others too that don’t matter here).void MyMethod(string)."aaa"and therefore when compiling code of the formMyMethod()if no method matchingMyMethod()can be found, you may replace it with a call to `MyMethod(“aaa”).So, that’s what the call in
BBBdoes: The compiler sees a call toMyMethod(), doesn’t find a methodMyMethod()but does find a methodMyMethod(string). It also sees that at the place where it is defined there’s a default value of “aaa”, so at compile time it changes this to a call toMyMethod("aaa").From within
BBB,AAAis considered the place whereAAA‘s methods are defined, even if overridden inBBB, so that they can be over-ridden.At run-time,
MyMethod(string)is called with the argument “aaa”. Because there is a overridden form, that is the form called, but it is not called with “bbb” because that value has nothing to do with the run-time implementation but with the compile-time definition.Adding
this.changes which definition is examined, and so changes what argument is used in the call.Edit: Why this seems more intuitive to me.
Personally, and since I’m talking of what is intuitive it can only be personal, I find this more intuitive for the following reason:
If I was coding
BBBthen whether calling or overridingMyMethod(string), I’d think of that as “doingAAAstuff” – it’sBBBs take on “doingAAAstuff”, but it’s doingAAAstuff all the same. Hence whether calling or overriding, I’m going to be aware of the fact that it wasAAAthat definedMyMethod(string).If I was calling code that used
BBB, I’d think of “usingBBBstuff”. I might not be very aware of which was originally defined inAAA, and I’d perhaps think of this as merely an implementation detail (if I didn’t also use theAAAinterface nearby).The compiler’s behaviour matches my intuition, which is why when first reading the question it seemed to me that Mono had a bug. Upon consideration, I can’t see how either fulfils the specified behaviour better than the other.
For that matter though, while remaining at a personal level, I’d never use optional parameters with abstract, virtual or overridden methods, and if overriding someone else’s that did, I’d match theirs.