9

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 つあるのはなぜですか?

ありがとう。

4

2 に答える 2

5

C# 仕様によると、コンパイラは SelectMany の最初のバージョンへのオーバーロード呼び出しを生成しません。SelectMany の最初のバージョンは、リストのリストを 1 つのフラット リストにフラット化するのに役立ちます。

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

クエリ式には強い同等のものはありません。

詳細については、C# 言語仕様のセクション 7.15.2 を参照してください。

于 2009-01-08T02:56:04.750 に答える
5

SelectMany のシグネチャが 2 つあるのはなぜですか?

したがって、コードで最初のものを使用できます。

var orders = Customers.SelectMany(c => c.Orders)
于 2009-01-09T15:29:31.413 に答える