Разрешение метода C #, long против int - PullRequest
39 голосов
/ 25 мая 2011
class foo
{
  public void bar(int i) { ... };
  public void bar(long i) { ... };
}


foo.bar(10);

Я ожидаю, что этот код выдаст мне какую-то ошибку или хотя бы предупреждение, но не так ...

Какая версия bar () называется и почему?

Ответы [ 3 ]

54 голосов
/ 25 мая 2011

Вызывается int-версия bar, потому что 10 является литералом int, и компилятор будет искать метод, наиболее близкий к входной переменной (-ям).Чтобы вызвать длинную версию, вам нужно указать длинный литерал, например, так: foo.bar(10L);

Это сообщение Эрика Липперта о гораздо более сложных версиях перегрузки методов.Я попытался бы объяснить это, но он делает намного лучшую работу, и я когда-либо мог: http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

из C # 4.0 Спецификация:

Перегрузка методов допускает несколько методов водин и тот же класс, чтобы иметь то же имя, если они имеют уникальные подписи.При компиляции вызова перегруженного метода компилятор использует разрешение перегрузки, чтобы определить конкретный метод для вызова.Разрешение перегрузки находит единственный метод, который наилучшим образом соответствует аргументам или сообщает об ошибке, если не может быть найдено ни одного наилучшего соответствия.В следующем примере показано действующее разрешение перегрузки.Комментарий для каждого вызова в методе Main показывает, какой метод фактически вызван.

 class Test {   
      static void F() {
        Console.WriteLine("F()");   
      }     
      static void F(object x) {
        Console.WriteLine("F(object)");     
      }
      static void F(int x) {
        Console.WriteLine("F(int)");    
      }
      static void F(double x) {
        Console.WriteLine("F(double)");     
      }
      static void F<T>(T x) {
        Console.WriteLine("F<T>(T)");   
      }
      static void F(double x, double y) {
        Console.WriteLine("F(double,double)");  
      }     

      static void Main() {
        F();                // Invokes F()
        F(1);           // Invokes F(int)
        F(1.0);         // Invokes F(double)
        F("abc");       // Invokes F(object)
        F((double)1);       // Invokes F(double)
        F((object)1);       // Invokes F(object)
        F<int>(1);      // Invokes F<T>(T)
        F(1, 1);        // Invokes F(double, double)
      } 
}

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

12 голосов
/ 25 мая 2011

Как говорит Кевин, существует процесс разрешения перегрузки. Основной эскиз процесса:

  • Идентифицирует все доступные методы-кандидаты, возможно, используя вывод типов в универсальных методах
  • Отфильтровать неприменимые методы; то есть методы, которые не могут работать, поскольку аргументы не преобразуются неявно в типы параметров.
  • Как только у нас будет набор подходящих кандидатов, запустите на них больше фильтров, чтобы определить единственного лучшего.

Фильтры довольно сложные. Например, метод, первоначально объявленный в более производном типе, всегда лучше, чем метод, первоначально объявленный в менее производном типе. Метод, в котором типы аргументов точно соответствуют типам параметров, лучше, чем метод с неточными совпадениями. И так далее. См. Спецификацию для точных правил.

В вашем конкретном примере алгоритм "Betterness" прост. Точное совпадение между int и int лучше, чем неточное совпадение между int и long.

4 голосов
/ 25 мая 2011

Я бы сказал, если вы превысите предел

-2,147,483,648 to 2,147,483,647

управление перейдет к long

Диапазон для long

–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

Максимальное значение для int

foo.bar(-2147483648);

или

foo.bar(2147483648);

Long получит контроль, если мы превысим значение на 2147483648

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