2010-05-04 5 views
9

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

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

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

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

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

+0

Он не использует 'var' ключевое слово. – SLaks

+2

@SLaks: Да, я знаю. –

+0

@SLaks: "'также' обычно видел ' – Dykam

5

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

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

17

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

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

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

+0

Обратите внимание, что если у вас есть два разных типа, которые расширяют «Parent», и вы пытаетесь сделать «What (a, b)» (где a и b относятся к этим двум различным типам), он не будет знать, чтобы вывести введите «Parent». –

+1

@BlueRaja: это фактически тот же случай, поскольку в примере Дена int и string являются расширениями Object. Принцип дизайна здесь заключается в том, что когда его попросят найти «лучший» элемент набора, C# всегда выбирает элемент из набора. Он никогда не выбирает участника извне набора. Если его спросят, что лучший член от {Tiger, Giraffe}, он не говорит «Animal», он говорит, что лучшего участника нет. –

1

компилятор достаточно умен, чтобы понять, что общий тип «INT»

7

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

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

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

Дополнительную информацию см. В разделе 7.4.2 спецификации C# 3.

2

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

2

Если вопрос о том, как это работает в 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

Смежные вопросы