Enumerable.SelectMany には 4 つのオーバーロードされたシグネチャがあります。簡単にするために、int引数を持つ 2 つの署名を無視します。したがって、SelectMany には 2 つの署名があります。
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# コンパイラは 2 番目の署名のみを選択するようです。最初の署名は使用されません。
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 つのタイプが含まれます。したがって、2 番目の SelectMany シグネチャを選択するのが合理的です。ただし、以下の例では、1 つのタイプのみが関与しており、2 番目の署名が選択されています。
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 であるという理由だけで存在しますか?
おそらく、次のような疑問が生じる可能性があります: SelectMany のシグネチャが 2 つあるのはなぜですか?
ありがとう。