Разница между OfType <> () и проверкой типа в расширении Where () - PullRequest
7 голосов
/ 26 января 2012

Кроме читабельности, в чем разница между следующими запросами linq и когда и почему я должен использовать один над другим:

IEnumerable<T> items = listOfItems.Where(d => d is T).Cast<T>();

и

IEnumerable<T> items = listOfItems.OfType<T>();

Обновление: Черт, извините, я добавил несколько ошибок при попытке упростить мою проблему

Ответы [ 4 ]

8 голосов
/ 26 января 2012

Давайте сравним три метода (обратите внимание на общие аргументы):

  1. listOfItems.Where(t => t is T), вызванный на IEnumerable<X>, все равно вернет IEnumerable<X> только что отфильтрованный, чтобы содержать только элементы типа T.

  2. listOfItems.OfType<T>(), вызванный IEnumerable<X>, вернет IEnumerable<T>, содержащий элементы, которые можно привести к типу T.

  3. listOfItems.Cast<T>(), вызванный IEnumerable<X>, вернет IEnumerable<T>, содержащий элементы, приведенные к типу T, или выдаст исключение, если какой-либо из элементов не может быть преобразован.

И listOfItems.Where(d => d is T).Cast<T>() в основном делает одно и то же дважды - Where фильтрует все элементы, которые T, но все еще оставляют тип IEnumerable<X>, а затем Cast снова пытается привести их к T, но это время возвращения IEumerable<T>.

3 голосов
/ 26 января 2012

Если я возьму несколько вольностей на вашем примере и проверю их в LINQPad, вот что я получу:

Методы

List<T> GetNumbers<T>(List<T> nums){
    return nums.Where(d => d is T).ToList<T>();
}

List<T> GetNumbersOfType<T>(List<T> nums){
    return nums.OfType<T>().ToList<T>();
}

IL

GetNumbers:
IL_0000:  ldarg.1     
IL_0001:  ldnull      
IL_0002:  ldftn       05 00 00 2B 
IL_0008:  newobj      0A 00 00 0A 
IL_000D:  call        06 00 00 2B 
IL_0012:  call        07 00 00 2B 
IL_0017:  ret         

GetNumbersOfType:
IL_0000:  ldarg.1     
IL_0001:  call        08 00 00 2B 
IL_0006:  call        07 00 00 2B 
IL_000B:  ret  

Я не эксперт по IL, но похоже, что метод GetNumbers (который использует синтаксис Where) создает новый объект каждый раз в цикле и поэтому, вероятно, потребляет немного больше памяти, чем GetNumbersOfType метод (который использует OfType).

3 голосов
/ 26 января 2012

listOfItems.Where(d => d is T) возвращает IEnumerable<U> (где U - тип элементов в listOfItems), содержащее только элементы типа T.

listOfItems.OfType<T>() возвращает IEnumerable<T>.

1 голос
/ 26 января 2012

По сути, нет никакой разницы для скомпилированного профиля времени выполнения скомпилированного кода. OfType<T> возвращает OfTypeIterator, который внутренне выполняет is тест, а yield return s - те, которые соответствуют.

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