There are 4 overloaded signatures for Enumerable.SelectMany. To make it simple, we ignore the two signatures with int argument. So we have 2 signatures for 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
)
My question is: how C# compiler choose SelectMany when translating LINQ expression to extension method invocation?
Basically, if there are multiple from in LINQ expression, there will be SelectMany. But, it seems that C# compiler only choose the second signature. The first signature is never used.
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);
}
With the help of Reflector, I can see that above LINQ expression is translated into
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();
})
Above example involves 3 types. So, it is reasonable to select the second SelectMany signature. However, for below example, only one type is involved, it still selects the second signature.
IEnumerable<int> en4 =
from i1 in en1
from i2 in Enumerable.Range(0, i1)
select i2;
It is translated into:
en1.SelectMany<int, int, int>(delegate (int i1) {
return Enumerable.Range(0, i1);
}, delegate (int i1, int i2) {
return i2;
})
So, I cannot find a case that LINQ expression is translated into the first SelectMany signature. Is there such case?
If the first SelectMany signature is not used, then it exists just because it is BIND of monad in functional programming?
Perhaps the question can be: why do we have 2 signatures of SelectMany?
Thanks.
According to the C# Spec, the compiler will not generate an overload call to the first version of SelectMany. The first version of SelectMany is useful for flattening a List of Lists into a single flat list.
public IEnumerable<string> Example(IEnumerable<IEnumerable<string>> enumerable) {
return enumerable.SelectMany(x => x);
}
It doesn't have a strong equivalent in a query expression.
See Section 7.15.2 of the C# Language Spec for more information.
why do we have 2 signatures of SelectMany?
So I can use the first one in my code.
var orders = Customers.SelectMany(c => c.Orders)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With