Как да си обясня това поведение с претоварени и заменени методи?

Може ли някой да бъде толкова мил и да ми обясни защо този код показва Derived.DoWork(double). Мога да намеря някои обяснения за това поведение, но искам някой да ми изясни това.

using System;

public class Base
{
    public virtual void DoWork(int param) {
        Console.WriteLine("Base.DoWork");
    }
}

public class Derived : Base
{
    public override void DoWork(int param) {
        Console.WriteLine("Derived.DoWork(int)");
    }

    public void DoWork(double param) {
        Console.WriteLine("Derived.DoWork(double)");
    }

    public static void Main() {
        int val = 5;
        Derived d = new Derived();
        d.DoWork(val);
    }
}

person mic4ael    schedule 12.05.2014    source източник
comment
Вижте 7.3 Търсене на членове Първо, наборът на всички достъпни (раздел 3.5) членове с име N, декларирани в T и базовите типове (раздел 7.3.1) на T е конструиран. Декларациите, които включват модификатор за отмяна, се изключват от набора. Ако не съществуват и са достъпни членове с име N, тогава търсенето не създава съвпадение и следващите стъпки не се оценяват.   -  person Habib    schedule 12.05.2014


Отговори (3)


Ерик Липърт винаги казваше "По-близо е по-добре".

Метод, деклариран за първи път в производен клас, е по-близък от метод, деклариран за първи път в базов клас.

Така че от връзката по-горе производният клас е по-близо, следователно е избран.

Това поведение се прилага внимателно, за да се избегне Проблем с крехък базов клас

За пълнота ще споделя топчетата:

  • Метод, деклариран за първи път в производен клас, е по-близък от метод, деклариран за първи път в базов клас.

  • Метод във вложен клас е по-близък от метод в съдържащ клас.

  • Всеки метод от приемащия тип е по-близък от всеки метод за разширение.

  • Метод за разширение, намерен в клас във вложено пространство от имена, е по-близък от метод за разширение, открит в клас във външно пространство от имена.

  • Метод за разширение, намерен в клас в текущото пространство от имена, е по-близък от метод за разширение, намерен в клас в пространство от имена, споменат от директива за използване.

  • Метод за разширение, намерен в клас в пространство от имена, споменат в директива за използване, където директивата е във вложено пространство за имена, е по-близък от метод за разширение, открит в клас в пространство за имена, споменат в директива за използване, където директивата е във външно пространство за имена.

person Sriram Sakthivel    schedule 12.05.2014
comment
Точно за този отговор си мислех! - person mic4ael; 12.05.2014
comment
Той предава цяло число в d.DoWork, така че трябва да се отпечатва Derived.DoWork(int), а не Derived.DoWork(double). - person Trisped; 12.05.2014
comment
Вижте също stackoverflow .com/questions/1451099/ - person John Saunders; 12.05.2014
comment
Все още бих очаквал метод с точно съвпадение на сигнатурата на метода да бъде по-близък от претоварване на производния клас с малко по-различна сигнатура. Живей и се учи предполагам. Сега трябва да видя какво прави VB... - person Bradley Uffner; 12.05.2014
comment
@Trisped Прочетете това внимателно Метод, деклариран за първи път в производен клас, е по-близък от метод, деклариран за първи път в базов клас, действителният метод е деклариран за първи път само в базов клас, така че предполагам, че не е по-близо. - person Sriram Sakthivel; 12.05.2014
comment
@Trisped, въпреки че Derived замества DoWork(int), компилаторът все още счита този метод за принадлежащ на Base. DoWork(double) е съвместим, тъй като int е имплицитно преобразуван към double и също е дефиниран в Derived, така че е по-близо. Като доказателство, ако промените Derived на new public void DoWork(int), ще видите, че ключовата дума new казва на компилатора да третира DoWork(int) като сега собственост на Derived и вместо това ще го съпостави. - person Ivaylo Slavov; 12.05.2014
comment
@BradleyUffner Работи по този начин, за да избегне проблема с крехкия базов клас. Вижте актуализираната връзка. - person Sriram Sakthivel; 12.05.2014
comment
Тествах го и в случай, че някой е любопитен, VB.NET извиква Integer версията. Интересен избор от различните езикови екипи. - person Bradley Uffner; 12.05.2014

Това поведение е дефинирано в спецификацията на езика C#, по-специално раздел 7.5.3 „Резолюция на претоварване“. Ето връзка към по-стара версия, в противен случай вижте CSharp Language Specification.docx, който трябва да имате локално, напр. C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC#\Specifications\1033\CSharp Language Specification.docx .

В този случай методите, маркирани като override, са изключени, поради което претоварването double е единствената валидна опция (акцентът е мой):

Всеки от тези контексти дефинира набора от кандидат функционални членове и списъка с аргументи по свой уникален начин, както е описано подробно в секциите, изброени по-горе. Например, наборът от кандидати за извикване на метод не включва методи, означени с отмяна (§7.4), а методите в базов клас не са кандидати, ако някой метод в производен клас е приложим (§7.6 .5.1).

person Ahmad Mageed    schedule 12.05.2014
comment
Любопитен съм дали ще има ситуации, в които точно това поведение ще бъде полезно и използвано нарочно? Поне дизайнерският екип на C# определено е имал нещо предвид. За хората, запознати с други ООП езици, като Java например (включително и мен), това поведение не е прозрачно и може би несправедливо се възприема като неразумно. - person Ivaylo Slavov; 12.05.2014
comment
Всъщност открих причината тук в блога на Ерик Липерт. Присъства и в един от отговорите на дублиран въпрос на StackOverflow . - person Ivaylo Slavov; 12.05.2014

Това поведение очевидно е проектирано:

'Когато избирате претоварване, ако има някакви съвместими методи, декларирани в производен клас, всички сигнатури, декларирани в базовия клас, се игнорират - дори ако са заменени в същия производен клас!' http://social.msdn.microsoft.com/Forums/vstudio/en-US/a70b25d4-f310-4d06-9dc2-a453f822f4f3/function-not-getting-called-when-overloading-the-function-of-base-class-in-derived-class-with?forum=csharpgeneral

person edtheprogrammerguy    schedule 12.05.2014