【发布时间】:2010-09-30 04:38:14
【问题描述】:
Enumerable.SelectMany 有 4 个重载签名。为了简单起见,我们忽略了带有 int 参数的两个签名。所以我们有 2 个 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
)
我的问题是:C# 编译器在将 LINQ 表达式转换为扩展方法调用时如何选择 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);
}
在Reflector的帮助下,我可以看到上面的LINQ表达式被翻译成
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();
})
以上示例涉及 3 种类型。因此,选择第二个 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 签名?
谢谢。
【问题讨论】:
标签: c# select expression linq