Има 4 претоварени подписа за Enumerable.SelectMany. За да го направим по-просто, игнорираме двата подписа с аргумент 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# компилаторът избира SelectMany, когато превежда LINQ израз в извикване на метод на разширение?
По принцип, ако има няколко от в LINQ израза, ще има 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 не се използва, тогава той съществува само защото е BIND на монада във функционалното програмиране?
Може би въпросът може да бъде: защо имаме 2 подписа на SelectMany?
Благодаря.