Тут варто зазначити одне, що замінена версія викликається кожного разу. Змініть заміну на:
public override void MyMethod(string s = "bbb")
{
Console.Write("derived: ");
base.MyMethod(s);
}
І результат:
derived: bbb
derived: aaa
Метод у класі може зробити одне або два з наступного:
- Він визначає інтерфейс для виклику іншого коду.
- Він визначає реалізацію, яка буде виконуватися при виклику.
Це може не робити і того, і іншого, оскільки абстрактний метод робить лише перший.
У BBB
рамках викликів MyMethod()
виклику використовується метод, визначений уAAA
.
Оскільки є перевизначення в BBB
, виклик цього методу призводить до реалізації у виклику BBB
.
Тепер визначення в AAA
повідомляє код виклику двох речей (ну, ще декількох, які тут не мають значення).
- Підпис
void MyMethod(string)
.
- (Для тих мов, які його підтримують) значенням за замовчуванням для одного параметра є,
"aaa"
і тому при компіляції коду форми, MyMethod()
якщо не MyMethod()
вдається знайти відповідний метод , ви можете замінити його викликом `MyMethod (" aaa ").
Отже, це те, що BBB
робить виклик : Компілятор бачить виклик MyMethod()
, не знаходить методу, MyMethod()
але знаходить метод MyMethod(string)
. Він також бачить, що там, де це визначено, є значення за замовчуванням "aaa", тому під час компіляції воно змінює це на виклик MyMethod("aaa")
.
Зсередини BBB
, AAA
вважається місцем , де AAA
визначені «S методи, навіть якщо переопределяется в BBB
, так що вони можуть бути перевизначені.
Під час виконання MyMethod(string)
викликається з аргументом "aaa". Оскільки існує перевизначена форма, ця форма називається, але вона не викликається з "bbb", оскільки це значення не має нічого спільного з реалізацією часу виконання, а з визначенням часу компіляції.
Додавання this.
змін, визначення яких перевіряється, і таким чином змінює аргумент, який використовується у виклику.
Редагувати: Чому це здається мені більш інтуїтивним.
Особисто, і оскільки я говорю про те, що є інтуїтивним, воно може бути лише особистим, я вважаю це більш інтуїтивним з наступної причини:
Якби я кодував, BBB
то виклик чи перевизначення MyMethod(string)
, я б вважав це як "робити AAA
речі" - це BBB
візьмемо на себе "робити AAA
речі", але це робити AAA
все одно. Отже, дзвінок чи перевизначення, я буду знати про те, що це було AAA
визначено MyMethod(string)
.
Якби я називав код, який використовував BBB
, я б подумав про "використання BBB
речей". Можливо, я не дуже обізнаний, що було спочатку визначено в AAA
, і, можливо, я вважав би це лише деталлю реалізації (якби я також не використовувавAAA
інтерфейс поруч).
Поведінка компілятора відповідає моїй інтуїції, саме тому при першому читанні запитання мені здалося, що у Моно була помилка. Після розгляду я не можу зрозуміти, як той чи інший виконує зазначену поведінку краще за інший.
Однак, залишаючись на особистому рівні, я ніколи не використовував би необов’язкові параметри з абстрактними, віртуальними або перевизначеними методами, і, якщо перевизначував чужі, це робило, я б збігався з їхніми.