Bemerkenswert ist hier, dass die überschriebene Version jedes Mal aufgerufen wird. Ändern Sie die Überschreibung in:
public override void MyMethod(string s = "bbb")
{
Console.Write("derived: ");
base.MyMethod(s);
}
Und die Ausgabe ist:
derived: bbb
derived: aaa
Eine Methode in einer Klasse kann eine oder zwei der folgenden Aktionen ausführen:
- Es definiert eine Schnittstelle, über die anderer Code aufgerufen werden kann.
- Es definiert eine Implementierung, die beim Aufruf ausgeführt werden soll.
Es kann nicht beides tun, da eine abstrakte Methode nur die erstere tut.
Innerhalb BBB
des Aufrufs MyMethod()
ruft eine Methode definiert in AAA
.
Da es eine Überschreibung gibt BBB
, führt der Aufruf dieser Methode dazu, dass eine Implementierung BBB
aufgerufen wird.
Die Definition in AAA
informiert den aufrufenden Code über zwei Dinge (nun, einige andere, die hier keine Rolle spielen).
- Die Unterschrift
void MyMethod(string)
.
- (Für die Sprachen, die dies unterstützen) Der Standardwert für den einzelnen Parameter ist.
"aaa"
Wenn beim Kompilieren des Codes des Formulars MyMethod()
keine Methodenübereinstimmung MyMethod()
gefunden werden kann, können Sie ihn durch einen Aufruf von "MyMethod" ("aaa") ersetzen.
Das macht der Aufruf BBB
also so: Der Compiler sieht einen Aufruf von MyMethod()
, findet keine Methode MyMethod()
, findet aber eine Methode MyMethod(string)
. Es wird auch angezeigt, dass an der Stelle, an der es definiert ist, der Standardwert "aaa" vorhanden ist. Bei der Kompilierung wird dies in einen Aufruf von geändert MyMethod("aaa")
.
Von innen BBB
, AAA
ist der Ort , an dem als AAA
‚s Methoden definiert werden, auch außer Kraft gesetzt , wenn in BBB
, so dass sie können außer Kraft gesetzt werden.
Wird zur Laufzeit MyMethod(string)
mit dem Argument "aaa" aufgerufen. Da es ein überschriebenes Formular gibt, wird dieses Formular aufgerufen, aber es wird nicht mit "bbb" aufgerufen, da dieser Wert nichts mit der Laufzeitimplementierung zu tun hat, sondern mit der Definition der Kompilierungszeit.
Durch this.
das Hinzufügen wird geändert, welche Definition untersucht wird, und somit wird geändert, welches Argument im Aufruf verwendet wird.
Edit: Warum mir das intuitiver erscheint.
Persönlich und da ich von dem spreche, was intuitiv ist, kann es nur persönlich sein, finde ich dies aus folgendem Grund intuitiver:
Wenn ich BBB
dann programmieren MyMethod(string)
würde, egal ob ich anrufe oder überschreibe , würde ich das als " AAA
Sachen machen" betrachten - es ist BBB
" AAA
Sachen machen", aber es macht trotzdem AAA
Sachen. Unabhängig davon, ob ich anrufe oder überschreibe, werde ich mir der Tatsache bewusst sein, dass es AAA
so definiert war MyMethod(string)
.
Wenn ich den verwendeten Code aufrufen BBB
würde, würde ich daran denken, " BBB
Sachen zu verwenden". Ich bin mir möglicherweise nicht sehr bewusst, in was ursprünglich definiert wurde AAA
, und ich würde dies möglicherweise nur als Implementierungsdetail betrachten (wenn ich nicht auch die AAA
Schnittstelle in der Nähe verwenden würde).
Das Verhalten des Compilers entspricht meiner Intuition, weshalb ich beim ersten Lesen der Frage den Eindruck hatte, dass Mono einen Fehler hatte. Bei Betrachtung kann ich nicht sehen, wie einer das angegebene Verhalten besser erfüllt als der andere.
Im Übrigen würde ich, während ich auf persönlicher Ebene bleibe, niemals optionale Parameter mit abstrakten, virtuellen oder überschriebenen Methoden verwenden, und wenn jemand anderes dies überschreibt, würde ich dessen entsprechen.