除了可读性之外,以下linq查询之间的区别是什么,以及何时以及为什么我将使用其中一个:
IEnumerable<T> items = listOfItems.Where(d => d is T).Cast<T>();
和
IEnumerable<T> items = listOfItems.OfType<T>();
更新 Dang,抱歉在尝试简化我的问题时介绍了一些错误
答案 0 :(得分:8)
让我们比较三种方法(注意泛型参数):
listOfItems.Where(t => t is T)
上调用的 IEnumerable<X>
仍会返回IEnumerable<X>
,只会过滤为仅包含T
类型的元素。
listOfItems.OfType<T>()
上调用的 IEnumerable<X>
将返回包含可以投放到IEnumerable<T>
类型的元素的T
。
listOfItems.Cast<T>()
上调用的 IEnumerable<X>
将返回IEnumerable<T>
包含已转换为T
类型的元素,或者如果无法转换任何元素,则会抛出异常。
并且listOfItems.Where(d => d is T).Cast<T>()
基本上做了两次相同的事情 - Where
过滤了T
的所有元素,但仍然保留了IEnumerable<X>
类型然后再次Cast
尝试将它们转换为T
但这次返回IEumerable<T>
。
答案 1 :(得分:3)
如果我对你的例子采取一些自由并在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
)。
答案 2 :(得分:2)
listOfItems.Where(d => d is T)
返回IEnumerable<U>
(其中U是listOfItems中项目的类型),仅包含T类型的项目。
listOfItems.OfType<T>()
会返回IEnumerable<T>
。
答案 3 :(得分:1)
基本上,编译代码的编译运行时配置文件没有区别。 OfType<T>
会返回OfTypeIterator
,其内部执行is
测试,yield return
匹配。