Как объяснить это поведение с помощью перегруженных и переопределенных методов?

Может ли кто-нибудь быть таким хорошим и объяснить мне, почему этот код показывает 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);
    }
}

Ответы

Ответ 1

Эрик Липперт всегда говорил "Ближе лучше" .

Метод, впервые объявленный в производном классе, ближе, чем метод, впервые объявленный в базовом классе.

Итак, из приведенной выше ссылки производный класс ближе и, следовательно, выбран.

Это поведение тщательно выполняется, чтобы избежать Проблема с хрупким базовым классом

Для полноты я буду делиться пулями:

  • Метод, впервые объявленный в производном классе, ближе, чем метод, впервые объявленный в базовом классе.

  • Метод в вложенном классе ближе, чем метод в содержащем классе.

  • Любой метод типа приема ближе любого метода расширения.

  • Метод расширения, найденный в классе во вложенном пространстве имен, ближе, чем метод расширения, найденный в классе во внешнем пространстве имен.

  • Метод расширения, найденный в классе в текущем пространстве имен, ближе, чем метод расширения, найденный в классе в пространстве имен, указанном директивой using.

  • Метод расширения, найденный в классе в пространстве имен, упомянутом в директиве using, где директива находится в вложенном пространстве имен, ближе, чем метод расширения, найденный в классе в пространстве имен, упомянутом в директиве using, где директива находится во внешнем пространстве имен.

Ответ 2

Это поведение определено в Спецификации языка С#, в частности в разделе 7.5.3 "Разрешение перегрузки". Здесь ссылка на более старую версию, в противном случае обратитесь к языку Specification.docx языка CSharp, который вы должны иметь локально, например C:\Program Files ( x86)\Microsoft Visual Studio 12.0\VС#\Specifications\1033\CSharp Language Specification.docx.

В этом случае исключенные методы отмечены переопределением, поэтому перегрузка double является единственным допустимым параметром (выделение мое):

Каждый из этих контекстов определяет набор элементов-кандидатов-кандидатов и список аргументов по-своему, как описано в подробно в разделах, перечисленных выше. Например, набор кандидаты на вызов метода не включают методы, отмеченные переопределить (§7.4), а методы в базовом классе не являются кандидатами, если таковые имеются метод в производном классе применим (§7.6.5.1).

Ответ 3

Это, по-видимому, по дизайну:

'При выборе перегрузки, если есть какие-либо совместимые методы, объявленные в производном классе, все сигнатуры, объявленные в базовом классе, игнорируются - даже если они переопределены в одном и том же производном классе! " 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