Тут варто зазначити одне, що замінена версія викликається кожного разу. Змініть заміну на:
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 інтерфейс поруч).
Поведінка компілятора відповідає моїй інтуїції, саме тому при першому читанні запитання мені здалося, що у Моно була помилка. Після розгляду я не можу зрозуміти, як той чи інший виконує зазначену поведінку краще за інший.
Однак, залишаючись на особистому рівні, я ніколи не використовував би необов’язкові параметри з абстрактними, віртуальними або перевизначеними методами, і, якщо перевизначував чужі, це робило, я б збігався з їхніми.