Почему это работает? - PullRequest
       37

Почему это работает?

10 голосов
/ 04 мая 2010

Почему это работает? Я не жалуюсь, просто хочу знать.

void Test()
{    
    int a = 1;
    int b = 2;

    What<int>(a, b);
    // Why does this next line work?
    What(a, b);
}

void What<T>(T a, T b)
{

}

Ответы [ 7 ]

18 голосов
/ 04 мая 2010

Это работает, потому что a и b являются целыми числами, поэтому компилятор может вывести аргумент универсального типа для What.

В C # 3 компилятор также может выводить аргумент типа, даже если типы не совпадают, если имеет смысл расширение преобразования. Например, если c было long, то What(a, c) будет интерпретироваться как What<long>.

Обратите внимание: если бы, скажем, c было string, это не сработало бы.

7 голосов
/ 04 мая 2010

Используется вывод типа для универсальных методов. Обратите внимание, что это изменилось между C # 2 и 3. Например, это не сработало бы в C # 2:

What("hello", new object());

... тогда как в C # 3 (или 4). В C # 2 вывод типа выполнялся для каждого аргумента, и результаты должны были точно совпадать. В C # 3 каждый аргумент вносит информацию, которая затем складывается, чтобы вывести аргументы типа. C # 3 также поддерживает вывод типа многофазный , где компилятор может обработать один аргумент типа, а затем посмотреть, есть ли у него дополнительная информация об остальном (например, из-за лямбда-выражений с неявными типами параметров). В основном это продолжается до тех пор, пока он не может получить больше информации, или он заканчивает - или видит противоречивую информацию. Вывод типа в C # не такой мощный, как алгоритм Хиндли-Милнера , но он работает лучше в других отношениях (в частности, он всегда продвигается вперед).

См. Раздел 7.4.2 спецификации C # 3 для получения дополнительной информации.

7 голосов
/ 04 мая 2010

Компилятор C # поддерживает вывод типов для обобщенных типов, а также обычно используется при использовании ключевого слова var.

Здесь int выводится из контекста (a и b), поэтому <int> не требуется. Это делает код чище и легче читать в разы.

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

5 голосов
/ 04 мая 2010

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

Эта функция значительно упрощает вызовы LINQ. (Вам не нужно писать numbers.Select<int, string>(i => i.ToString()), потому что компилятор выводит int из numbers и string из ToString)

2 голосов
/ 04 мая 2010

Если вам интересна тема о том, как это работает в C # 3.0, вот небольшое видео, где я объясняю это в далеком 2006 году, когда мы впервые разрабатывали версию функции для C # 3.0.

http://blogs.msdn.com/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx

См. Также раздел "вывод типа" моего блога:

http://blogs.msdn.com/ericlippert/archive/tags/Type+Inference/default.aspx

2 голосов
/ 04 мая 2010

Компилятор может вывести тип T как int, поскольку оба параметра, передаваемые в What (), имеют тип int. Вы заметите, что многие расширения Linq определены с помощью обобщений (как IEnumerable), но обычно используются так, как вы показываете.

1 голос
/ 04 мая 2010

Компилятор достаточно умен, чтобы понять, что универсальный тип - int

...