LINQ保证订购SelectMany?

我有一个有序的枚举数组IorderedEnumerable[] foo我想要展平它,以便foo的有序枚举按照它们存储在数组中的顺序连接在一起。

例如{{1,2,3},{4,5},{6}} => {1,2,3,4,5,6}

我可以通过IOrderedEnumerable bar = foo.SelectMany(x => x); 或者LINQ不能保证在展平时如何处理订单?

列表(由.net中的IEnumerable表示)以及两个操作组成一个monad,它必须遵守monad定律 。 这两个操作在不同的语言中被赋予不同的名称,维基百科文章使用Haskell,它们return其称为return>>= (称为“bind”)。 C#调用>>= SelectMany ,没有用于return的内置函数。 这些名称并不重要,重要的是类型。 专门针对IEnumerable这些是:

 Return :: T -> IEnumerable SelectMany :: IEnumerable -> Func> -> IEnumerable 

Return只返回包含给定元素的1元素序列,例如

 public static IEnumerable Return(T item) { return new[] { item }; } 

SelectMany已经实现为Enumerable.SelectMany

 public static IEnumerable SelectMany(IEnumerable seq, Func> f) { ... } 

SelectMany接受一个输入序列和一个函数,该函数为输入序列的每个项生成另一个序列,并将得到的序列序列展平为一个序列。

在C#重述前两个monad法则我们有:

左派身份

 Func> f = ... Return(x).SelectMany(f) == f(x) 

正确的身份

 IEnumerable seq = ... seq.SelectMany(Return) == seq 

通过正确的身份定律, SelectMany必须根据输入元素的顺序展平由Func>生成的每个序列。

假设它以相反的顺序扁平化它们,例如

 new[] { 1, 2 }.SelectMany(i => new[] { i, -i }) == new[] { 2, -2, 1, -1 } 

然后

 var s = new[] { 1, 2 } s.SelectMany(Return) == new[] { 2, 1 } != s 

这不符合所要求的权利身份法。

所有LINQ to Objects方法(显然, OrderBy()ToDictionary()除外)将保留源排序。