Процесс вывода типа немного сложен;см. главу 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