Подтвердить что ты не робот

С# Разрешение метода, long vs int

class foo
{
  public void bar(int i) { ... };
  public void bar(long i) { ... };
}


foo.bar(10);

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

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

4b9b3361

Ответ 1

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

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

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

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

 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)
      } 
}

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

Ответ 2

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

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

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

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

Ответ 3

Я бы сказал, если вы превысите лимит ниже

-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