Ну, вы оставили самую важную часть, которая заставляет все это работать. Параметры типа можно судить по фактическим параметрам объектов, передаваемых в
Например:.
static class Extensions {
internal static IEnumerable<U> Test<T, U>(
this IEnumerable<T> items,
Func<T, U> converter) {
foreach (T item in items) {
yield return converter(item);
}
}
}
Это расширение методы работают на любом IEnumerable класса и преобразуют каждый элемент в перечислении к другому типу на основе на конвертере, который вы предоставили. Это стандартные дженерики.
Теперь, есть много способов, чтобы вызвать этот метод:
IEnumerable<int> values = Enumerable.Range<int>(1, 10);
Func<int, string> converter = i => i.ToString("0.00");
// Variation 1, explicit calling
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter);
// Variation 2, explicit calling with type inference
IEnumerable<string> results2 = Extensions.Test(values, converter);
// Variation 3, extension method calling, still providing explicit types
IEnumerable<string> results3 = values.Test<int, string>(converter);
// Variation 4, extension method with type inference
IEnumerable<string> results4 = values.Test(converter);
Все четыре вариации называют один и тот же метод и возвращает один и тот же результат. Вывод типа работает, просматривая переданные параметры и автоматически вызывая их типы на основе того, что предоставляется. В наших примерах выше, он может определить, что тип T
имеет тип int
, потому что мы передали в IEnumerable<int>
в параметр для IEnumerable<T>
. Также можно сделать вывод о том, что тип U
имеет тип string
, потому что мы передали в Func соответствующий начальный тип T
с int
и возвращаем строку. Таким образом, Func<T, U>
заполнен нашей функцией преобразователя Func<int, string>
.
Из вышесказанного, это стандартный общий метод в этой точке. Тип вывода и методы расширения - не что иное, как удобство/синтаксический сахар.Фактически, если вы декомпилируете вывод, вы можете увидеть, что методы расширения заменяются статическими вызовами и обычно определяются с явно заполненными параметрами типа. (Это зависит от вашего декомпилятора и опций набора).
Я могу ответить # 1 достаточно просто. Это позволяет методу работать с любым типом коллекции, а не только для строк или ints или Foos или что-то еще. Он также позволяет сравнивать с любым типом значения, пусть это будет int или строка или панель или [...]. В вашем конкретном случае вам просто нужно было выбрать 'int' из массива какого-то типа (который я даже не знал имени вашего ума). Используя generics, он будет работать не только для вашего одного случая, но и для любого подобного случая, который имеет ту же проблему, но с разными типами. Это будет более полезно для будущих посетителей, которые найдут ваш вопрос. – Servy
@Servy спасибо! Для будущих читателей я также нашел этот пост: http://stackoverflow.com/questions/4885027/how-does-generic-type-inference-work-in-c –