2009-01-08 57 views
9

Enumerable.SelectMany有4个重载签名。为了简单起见,我们忽略了两个签名int的说法。因此,我们有2个签名的SelectMany:C#编译器在翻译LINQ表达式时如何选择SelectMany?

public static IEnumerable<TResult> SelectMany<TSource, TResult>(
    this IEnumerable<TSource> source, 
    Func<TSource, IEnumerable<TResult>> selector 
) 

public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
    this IEnumerable<TSource> source, 
    Func<TSource, IEnumerable<TCollection>> collectionSelector, 
    Func<TSource, TCollection, TResult> resultSelector 
) 

我的问题是:如何翻译LINQ表达式来扩展方法调用时,C#编译器选择的SelectMany?

基本上,如果在LINQ表达式中有多个from,将会出现SelectMany。但是,似乎C#编译器只选择第二个签名。第一个签名从不使用。

 IEnumerable<int> en1 = Enumerable.Range(1, 3); 
     IEnumerable<double> en2 = new double[] { 1.0, 3.14 }; 

     IEnumerable<string> en3 = 
      from i1 in en1 
      from i2 in en2 
      select (i1 * i2).ToString(); 

     foreach (var i in en3) 
     { 
      Console.WriteLine(i); 
     } 

随着反射器的帮助下,我可以看到,上述LINQ表达以上示例涉及3种类型的被转换成

en1.SelectMany<int, double, string>(delegate (int i1) { 
     return en2; 
    }, delegate (int i1, double i2) { 
     double CS$0$0000 = i1 * i2return CS$0$0000.ToString(); 
    }) 

。所以,选择第二个SelectMany签名是合理的。但是,对于下面的例子,只涉及一种类型,它仍然选择第二个签名。

 IEnumerable<int> en4 = 
      from i1 in en1 
      from i2 in Enumerable.Range(0, i1) 
      select i2; 

它翻译成:

en1.SelectMany<int, int, int>(delegate (int i1) { 
     return Enumerable.Range(0, i1); 
    }, delegate (int i1, int i2) { 
     return i2; 
    }) 

所以,我无法找到的情况下LINQ表达式转换为第一署名的SelectMany。有这种情况吗?

如果没有使用第一个SelectMany签名,那么它的存在只是因为它在函数式编程中是monad的BIND?

也许问题可能是:为什么我们有2个SelectMany签名?

谢谢。

回答

5

根据C#Spec,编译器不会生成对SelectMany的第一个版本的重载调用。 SelectMany的第一个版本对于将List列表展平为单个平面列表非常有用。

public IEnumerable<string> Example(IEnumerable<IEnumerable<string>> enumerable) { 
    return enumerable.SelectMany(x => x); 
} 

它在查询表达式中没有很强的等价性。

有关更多信息,请参见C#语言规范的第7.15.2节。

+1

真的......一个void函数返回一些东西,没有人对它进行评论? – 2010-07-20 15:49:31

5

为什么我们有2个SelectMany签名?

所以我可以在我的代码中使用第一个。

var orders = Customers.SelectMany(c => c.Orders) 
+0

当然。这只是为了方便。 – 2009-11-18 19:07:34