Почему перегруженные методы имеют более низкий приоритет, чем метод экземпляра

У меня есть базовый класс A

public class A
{
    public virtual void Method(A parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
    public virtual void Method(B parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
}

Inhereted B

public class B : A
{
    public virtual void Method(object parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }

    public override void Method(A parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }

    public override void Method(B parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
}

Статический класс S с методом расширения

public static class S
{
    public static void Method(this B instance, B parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
}

Пример: мы создаем экземпляр типа B и вызываем Method на нем, мы ожидаем, что он будет public override void Method(B parameter) действительным результатом public virtual void Method(object parameter).

var b = new B();
b.Method(new B()); // B.Method (Object parameter) Why???

Почему компилятор не выбирает более подходящий метод??? UPD И почему это не метод расширения?

Ответ 1

Почему компилятор не выбирает более подходящий метод?

Поскольку он соответствует правилам спецификации языка, где любые методы-кандидаты, первоначально объявленные в базовом классе (если они переопределены в производном классе), игнорируются при поиске метода-кандидата, если только производный класс не имеют какие-либо применимые методы, после чего поиск перемещается до базового класса и т.д.

Это чтобы избежать проблемы с "хрупким базовым классом" , но я считаю, что трудно усвоить перед лицом переопределенного метода в производном классе.

Соответствующий бит спецификации С# 4 равен 7.4, который заканчивается следующим:

Для поиска членов в типах, отличных от параметров и интерфейсов типа, и поиска элементов в интерфейсах, которые строго однонаправленны (каждый интерфейс в цепочке наследования имеет ровно нулевой или один прямой базовый интерфейс), эффект правил поиска просто производные члены скрывают базовые элементы с тем же именем или подписью.

EDIT: О методах расширения...

И почему это не метод расширения?

Из раздела 7.6.5.2 спецификации:

В вызове метода (п. 7.5.5.1) одной из форм

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )

если нормальная обработка вызова не находит применимых методов, делается попытка обработать конструкцию как вызов метода расширения

Таким образом, метод расширения используется в основном как последнее средство.