2013-01-15 2 views
0

Мне довольно удобно с дженериками, но, будучи человеком, которому нравится понимать каждую деталь, у меня есть этот вопрос. В моей реализации метода Where расширения LINQОбщий вывод типа

public static class Extensions 
    { 
     public static IEnumerable<T> Where<T>(
         this IEnumerable<T> source, Func<T, bool> predicate) 
     { 
      foreach (T element in source) 
       if (predicate(element)) 
        yield return element; 
     } 
    } 

почему в Where<T> необходимости T? Почему тип не может быть выведен из T в IEnumerable<T>? Иными словами, почему подпись не может быть

public static IEnumerable<T> Where(this IEnumerable<T> source, Func<T, bool> predicate) 

Спасибо за любую помощь.

+0

Я думаю, что он может, но он есть там, где он не может. Вы можете использовать 'Where', не поставляя' T' в большинстве случаев. –

+0

@JonathanWood: Он говорит о подписи декларации, а не о вызове. –

+1

Ну, для того, чтобы когда-либо быть в состоянии предоставить 'T', в любом случае это должно быть в декларации. Что я упустил? –

ответ

1

<T> предварив список аргументов действует немного как «объявление переменной» - как вы не можете просто сказать:

x = 10; 

Вы должны объявить эту переменную первой:

int x = 10; 

Это просто объявление переменной для Type.

Теперь использования, это совсем другое дело - компилятор сделает это damnedest, чтобы попытаться сделать вывод, что «ценность», чтобы придерживаться в каждом из этих Type переменных, на основе использования и существующих подписях, но эти подписи еще объявить.

4

public static IEnumerable<T> Where(this IEnumerable<T> source, Func<T, bool> predicate)

С такой подписью, T бы необъявленный идентификатор. Вы не можете просто использовать IEnumerable<T>, если T не определен нигде. Таким образом, вам нужен общий параметр T на уровне метода (или, альтернативно, класса) для IEnumerable<T>.

2

Нет причин, по которым T в IEnumerable<T> и Where<T> должны быть одинаковыми; вы говорите, что они должны указывать их как T

IEnumerable<T> - это то, что возвращается методом. Where<T> предназначен для определения того, какой общий тип используется в качестве параметров. Это можно мысленно представить себе те T могут быть различных типов, если вы не указали их как в качестве T

То есть: Возвращаемый тип (IEnumerable<T>) не обязательно связаны с типами параметров (T в Where<T>) ,

0
public static class Foo 
{ 
    public static T Bar<T>(T input) { return input; } 
} 

Обычно тип будет выведен.

Foo.Bar("test"); 

Но что происходит в этом случае?

Foo.Bar(null); //error 

Аргументы типа не могут быть выведены, и если бы это было во время компиляции, вы получили ошибку компиляции.

Foo.Bar<string>(null); //works 
1

Вы смешиваете определения метода Where<T> и использования него.

Когда определяет (и объявляет) функцию, вам нужен параметр типа, чтобы показать компилятору, что метод является общим. Когда вы объявили параметр типа T, вы можете использовать его для отображения типов ввода входных и выходных аргументов (в данном случае IEnumerable<T>).

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

var numbers = new List<int> { 1, 2, 3, 4, 5 }; 
var odds = numbers.Where(x => x % 2 != 0); 

// test for example odds is IEnumerable<int> if you want confirmation =) 
Смежные вопросы