无论我用作输入的集合类型,LINQ始终返回IEnumerable<MyType>
而不是List<MyType>
或HashSet<MyType>
。
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
// numQuery is an IEnumerable<int> <====== Why IEnumerable<int> instead of int[]?
var numQuery =
from num in numbers
where (num % 2) == 0
select num;
我想知道决定不保留集合类型(如元素类型)的原因是什么,而不是建议的解决方法。
我知道存在toArray
,toDictionary
或toList
,这不是问题。
编辑:C#中的实现与Scala的工作方式有何不同,而不会覆盖各处的返回类型?
答案 0 :(得分:7)
Linq标准查询运算符在IEnumerable<T>
上定义,而不是在任何其他特定集合类型上定义。它适用于大多数集合,因为它们都实现了IEnumerable<T>
。
这些标准查询运算符的输出是一个新的IEnumerable<T>
- 如果要支持所有可用的集合,则需要这些标准查询运算符的 N实现,而不仅仅是一个。
Linq的许多方面,如懒惰评估,如果被迫工作,即List<T>
而不是IEnumerable<T>
,则效果不佳。
答案 1 :(得分:3)
简答: C#的类型系统过于原始,不支持在高阶函数中保留集合类型(没有代码重复,即)。
答案很长:请参阅我的帖子here。 (实际上它是关于Java的,但也适用于C#。)
答案 2 :(得分:1)
在LINQ-to-objects的特定情况下,LINQ-provider是System.Linq.Enumerable
类中定义的一组扩展方法。为了尽可能通用,它们被定义为扩展实现IEnumerable<T>
接口的任何类型。因此,当执行这些方法时,他们不知道集合是哪种具体类型;它只知道它是IEnumerable<T>
。因此,无法保证对集合执行的操作生成相同类型的集合。相反,它产生了下一个最好的东西 - IEnumerable<T>
对象。
这是一个非常具体的设计选择。 LINQ旨在以非常高的抽象级别工作。它的存在使您不必关心基础数据源,而只需说出您想要的内容而不关心这些细节。
答案 3 :(得分:0)
LINQ采用IEnumerable&lt;&gt;并返回一个。很自然。 IEnumerable是LINQ采用的原因 - 几乎所有集合都实现它。
答案 4 :(得分:0)
许多System.Linq.Enumerable方法被懒惰地评估。这允许您在不执行查询的情况下创建查询。
//a big array - have to start somewhere
int[] source = Enumerable.Range(0, 1000000).ToArray();
var query1 = source.Where(i => i % 2 == 1); //500000 elements
var query2 = query1.Select(i => i.ToString()); //500000 elements
var query3 = query2.Where(i => i.StartsWith("2"); //50000? elements
var query4 = query3.Take(5); //5 elements
string[] result = query4.ToArray();
此代码调用ToString大约15次。它分配一个字符串[5]数组。
如果Where和Select返回的数组,此代码将调用ToString 500000次并且必须分配两个大型数组。谢天谢地,事实并非如此。