Почему следующий общий вызов метода не требует типа? - PullRequest
2 голосов
/ 02 апреля 2011

Извините - не уверен в правильном имени, пожалуйста, измените, если вы можете думать о лучшем.

Я пытаюсь узнать немного больше о IEnumerable / collection / generics, и мне показалось, что я чего-то добиваюсь, пока меня не получил этот пример:

 var nums = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10 };

 var result = FilterNums(nums, i => i % 2 != 0);

.....

public static IEnumerable<T1> FilterNums<T1>(IEnumerable<T1> numslist, Func<T1, bool> predicateDelegate)

.....

Почему работает звонок на FilterNums? Если я изменю его на FilterNums<int>, он все равно будет работать, и это именно то, что я ожидал напечатать.

Итак, это как-то как обнаружить T1 для лямбда-запроса и не требует от меня его написания, или что-то еще происходит?

Ответы [ 2 ]

8 голосов
/ 03 апреля 2011

Процесс вывода типа немного сложен;см. главу 7 спецификации C # для точных деталей.

Вкратце это работает следующим образом.

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

Далеемы проверяем, являются ли какие-либо из них общими.Если это так, то мы пытаемся выяснить, могут ли аргументы универсального типа быть выведены из фактических аргументов.Процесс вывода идет следующим образом.Предположим, у вас есть список аргументов A:

A: (nums, i => i%2 != 0)

и список типов формальных параметров P:

P: (IEnumerable<T1>, Func<T1, bool>)

и набор параметров универсального типа X:

X: <T1>

Цель вывода типа состоит в том, чтобы сделать выводы от каждого члена A к соответствующему члену P, чтобы вывести достаточно информации о каждом члене X.

Эта конкретная проблема проста.Из первого аргумента мы видим, что тип чисел int [].Мы видим, что первый формальный параметр в P равен IEnumerable<T1>.Мы знаем, что int [] преобразуем в IEnumerable<int>, и, следовательно, T1 может быть int.Мы отмечаем этот факт.

И на этом мы в основном закончили.У нас нет ничего о T1, что мы можем вывести из второй пары аргумент / параметр.Вывод типа выполняется успешно и определяет, что T1 является int.Итак, мы притворяемся, что вы вызвали его с <int> в качестве списка аргументов типа.

Это была очень простая проблема вывода типа.Подумайте над этим:

A: (customers, c=>c.Name)
P: (IEnumerable<T>, Func<T, R>)
X: <T, R>

Это проблема, с которой вы сталкиваетесь, когда делаете customers.Select(c=>c.Name).

Что мы делаем?Из первого аргумента мы выводим «клиенты реализуют IEnumerable<Customer>, поэтому T, вероятно, является клиентом». После , сделав этот вывод, мы можем затем сказать, что «c в лямбде - это, следовательно, Customer. Следовательно, это лямбда от Customer для любого типа Customer.Name. Это строка. Следовательно, R - строка».

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

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

Если эта тема вас интересует, я много об этом писал.См.

http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/

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

http://wm.microsoft.com/ms/msdn/visualcsharp/eric_lippert_2006_11/EricLippert01.wmv

6 голосов
/ 02 апреля 2011

Это из-за вывода типа.

Компилятор понимает, что вы отправляете int, поэтому он неявно устанавливает универсальный тип в int. Если вы посмотрите на intellisense, то увидите, что ваш общий тип установлен как int.

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