Почему компилятор C # не кодирует ошибку, когда статический метод вызывает метод экземпляра?

В следующем коде есть статический метод Foo(), вызывающий метод экземпляра, Bar():

public sealed class Example
{
    int count;

    public static void Foo( dynamic x )
    {
        Bar(x);
    }

    void Bar( dynamic x )
    {
        count++;
    }
}

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

Так почему наличие динамического параметра позволяет компилировать код? ReSharper также не показывает это как ошибку.

Изменить 1: * в Visual Studio 2008

Изменить 2: добавил sealed, так как вполне возможно, что подкласс может содержать статический Bar(...). Даже запечатанная версия компилируется, когда невозможно, чтобы во время выполнения был вызван любой метод, кроме метода экземпляра.

108 голосов | спросил Mike Scott 11 +04002012-10-11T19:05:08+04:00312012bEurope/MoscowThu, 11 Oct 2012 19:05:08 +0400 2012, 19:05:08

3 ответа


0

По какой-то причине разрешение перегрузки всегда находит наилучшее соответствие перед , проверяя статическое или нестатическое. Пожалуйста, попробуйте этот код со всеми статическими типами:

class SillyStuff
{
  static void SameName(object o) { }
  void SameName(string s) { }

  public static void Test()
  {
    SameName("Hi mom");
  }
}

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

Дополнение: поэтому я думаю, что объяснение примера исходного кода dynamic состоит в том, что для обеспечения согласованности типов динамически мы также первые находим наилучшую перегрузку (проверяем только номер параметра и типы параметров и т. д., не статические и не статические), и только затем проверяем статические. Но это означает, что статическая проверка должна ждать до времени выполнения. Отсюда и наблюдаемое поведение.

Позднее добавление: некоторые предыстории того, почему они решили делать такие забавные вещи, могут быть выведены из это сообщение в блоге Эрика Липперта .

ответил Jeppe Stig Nielsen 11 +04002012-10-11T20:00:08+04:00312012bEurope/MoscowThu, 11 Oct 2012 20:00:08 +0400 2012, 20:00:08
0

Foo имеет параметр "x", который является динамическим, что означает, что Bar (x) является динамическим выражением.

Было бы вполне возможно, чтобы Пример имел такие методы:

static Bar(SomeType obj)

В этом случае правильный метод будет разрешен, поэтому утверждение Bar (x) совершенно корректно. Тот факт, что существует экземпляр метода Bar (x), не имеет значения и даже не рассматривается: по определению , поскольку Bar (x) является динамическим выражением, мы отложили разрешение во время выполнения.

ответил Marc Gravell 11 +04002012-10-11T19:17:23+04:00312012bEurope/MoscowThu, 11 Oct 2012 19:17:23 +0400 2012, 19:17:23
0

«Динамическое» выражение будет связано во время выполнения, поэтому если вы определите статический метод с правильной сигнатурой или методом экземпляра, компилятор не будет проверять его.

«Правильный» метод будет определен во время выполнения. Компилятор не может знать, существует ли допустимый метод во время выполнения.

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

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

class Program {
    static void Main(string[] args) {
        Example.Foo(1234);
        Example.Foo("1234");
    }
}
public class Example {
    int count;

    public static void Foo(dynamic x) {
        Bar(x);
    }

    public static void Bar(int a) {
        Console.WriteLine(a);
    }

    void Bar(dynamic x) {
        count++;
    }
}

Вы можете добавить метод для обработки всех «неправильных» вызовов, которые не могут быть обработаны

public class Example {
    int count;

    public static void Foo(dynamic x) {
        Bar(x);
    }

    public static void Bar<T>(T a) {
        Console.WriteLine("Error handling:" + a);
    }

    public static void Bar(int a) {
        Console.WriteLine(a);
    }

    void Bar(dynamic x) {
        count++;
    }
}
ответил oberfreak 11 +04002012-10-11T19:14:05+04:00312012bEurope/MoscowThu, 11 Oct 2012 19:14:05 +0400 2012, 19:14:05

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132