OfType<>() 和 Where() 扩展中的检查类型之间的区别

本文关键字:区别 检查 类型 之间 Where OfType 扩展 | 更新日期: 2023-09-27 18:21:21

除了可读性之外,以下 linq 查询之间有什么区别,以及我何时以及为什么使用一个查询:

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

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

更新:Dang,很抱歉在尝试简化我的问题时引入了一些错误

OfType<>() 和 Where() 扩展中的检查类型之间的区别

我们比较三种方法(注意泛型参数(:

  1. IEnumerable<X>调用listOfItems.Where(t => t is T)仍将返回刚刚过滤为仅包含类型T元素IEnumerable<X>

  2. listOfItems.OfType<T>()调用IEnumerable<X>将返回包含可转换为类型 T 的元素IEnumerable<T>

  3. IEnumerable<X> 上调用listOfItems.Cast<T>()将返回包含转换为类型 T 的元素的IEnumerable<T>,或者在无法转换任何元素时引发异常。

listOfItems.Where(d => d is T).Cast<T>()基本上做了两次相同的事情 - Where过滤所有T但仍保留类型IEnumerable<X>的元素,然后Cast再次尝试将它们强制转换为T但这次返回IEumerable<T>

listOfItems.Where(d => d is T)返回一个IEnumerable<U>(其中 U 是 listOfItems 中项的类型(,仅包含 T 类型的项。

listOfItems.OfType<T>()返回一个IEnumerable<T>

如果我对你的示例进行一些自由,并在 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>();
}

利诺伊

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(消耗更多的内存。

本质上,编译代码的编译运行时配置文件没有区别。 OfType<T>返回一个在内部执行is测试并yield return匹配的测试的OfTypeIterator