Как вызвать переопределенный метод, который имеет перегрузки? - PullRequest
7 голосов
/ 02 апреля 2012

У меня есть следующий простой код

abstract class A
{
    public abstract void Test(Int32 value);
}

class B : A
{
    public override void Test(Int32 value)
    {
        Console.WriteLine("Int32");
    }

    public void Test(Double value)
    {
        Test((Int32)1);
    }
}

Когда я запускал этот код, строка Test ((Int32) 1) вызывает переполнение стека из-за бесконечной рекурсии. Единственный возможный способ правильно вызвать правильный метод (с целочисленным параметром), который я нашел, это

(this as A).Test(1);

Но это не подходит для меня, потому что оба метода Test общедоступны, и я хочу, чтобы пользователи могли вызывать оба метода?

Ответы [ 2 ]

5 голосов
/ 02 апреля 2012

Разрешение перегрузки метода в C # не всегда ведет себя так, как вы могли бы ожидать, но ваш код работает в соответствии со спецификацией (я написал в блоге об этом некоторое время назад).

Короче говоря, компилятор начинает с поиска методов, которые

  • имеют одинаковые имена (в вашем случае Test)
  • объявлены в типе (в вашем случае B) или один из его базовых типов
  • не объявляется с модификатором переопределения

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

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

Если вы хотите вызвать переопределенный метод, вам нужно сначала привести объект к его базовому типу.

4 голосов
/ 02 апреля 2012

К сожалению, чтобы вызвать ссылку A::Test(int) через B, необходим некоторый тип приведения.Пока компилятор C # видит ссылку через B, он выберет версию B::Test(double).

Немного менее уродливая версия выглядит следующим образом:

((A)this).Test(1);

Еще одна мысль - использовать приватный метод с другим именем, которое используется в обоих.

class B : A { 
  public override void Test(int i) {
    TestCore(i);
  }
  public void Test(double d) {
    TestCore(1);
  }
  private void TestCore(int i) {
    // Combined logic here
  }
}
...