2013-02-26 3 views
9

Таким образом, я наткнулся на ответ на Servy (https://stackoverflow.com/a/15098242/496680) и некоторые из его кода делает это:Что подразумевается общий тип параметров

public static int BinarySearch<TSource, TKey>(...) 

для метода расширения, но он называет это так:

arr.BinarySearch(...) 

Я спросил, и кто-то заметил, что это подразумеваемый общий параметр типа. Я googled их, но не нашел никакой информации о них. Я понимаю, как работают дженерики, но я не понимаю, как и когда их использовать.

  1. Почему сервиз используется ими по методу расширения?
  2. Есть ли более официальное название для них, которое я могу найти?
+2

Я могу ответить # 1 достаточно просто. Это позволяет методу работать с любым типом коллекции, а не только для строк или ints или Foos или что-то еще. Он также позволяет сравнивать с любым типом значения, пусть это будет int или строка или панель или [...]. В вашем конкретном случае вам просто нужно было выбрать 'int' из массива какого-то типа (который я даже не знал имени вашего ума). Используя generics, он будет работать не только для вашего одного случая, но и для любого подобного случая, который имеет ту же проблему, но с разными типами. Это будет более полезно для будущих посетителей, которые найдут ваш вопрос. – Servy

+0

@Servy спасибо! Для будущих читателей я также нашел этот пост: http://stackoverflow.com/questions/4885027/how-does-generic-type-inference-work-in-c –

ответ

10

Ну, вы оставили самую важную часть, которая заставляет все это работать. Параметры типа можно судить по фактическим параметрам объектов, передаваемых в

Например:.

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>.

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

+0

Для ваших последних двух примеров вам нужно опустить «значения» в качестве параметра. – Servy

+0

К сожалению, спасибо! Удивительно, что вы можете пропустить, когда вы не можете скомпилировать! – Joshua

+0

Отличное объяснение! благодаря! –

2

Термин, который я обычно слышу, это «тип вывода».

+0

Да, это называется «вывод типа». В [Generic Methods (Руководство по программированию на C#) есть базовый пример] (http://msdn.microsoft.com/en-us/library/twcad0zb.aspx), где говорится: _Вы можете также опустить аргумент типа и компилятор будет ** вывести ** это. Следующий вызов Swap эквивалентен предыдущему вызову: [...] Те же правила для вывода типа применяются к статическим методам и методам экземпляров. Компилятор может вывести параметры типа на основе аргументов метода, которые вы передаете; он не может вывести параметры типа только из ограничения или возвращаемого значения. [...] _ –

6
  1. Он использует generic method в этом случае, потому что это позволяет его метод работы с любым типом содержащегося в Collection<T>. Общий метод делает это очень гибким и применимым для любого типа. Он использует тип inferrence при вызове метода, потому что он упрощает код на сайте вызова.

  2. Автоматическая обработка называется Type Inferrence и подробно описана в Спецификации языка C#, раздел 7.5.2: Введите Inferrence. Если вы хотите понять это подробно, я бы порекомендовал скачать C# language specification.