In che modo il compilatore C # sceglie SelectMany durante la traduzione dell'espressione LINQ?

StackOverflow https://stackoverflow.com/questions/422958

  •  05-07-2019
  •  | 
  •  

Domanda

Esistono 4 firme sovraccaricate per Enumerable.SelectMany. Per semplificare, ignoriamo le due firme con l'argomento int . Quindi abbiamo 2 firme per 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
)

La mia domanda è: in che modo il compilatore C # sceglie SelectMany quando traduce l'espressione LINQ in invocazione del metodo di estensione?

Fondamentalmente, se ci sono più da nell'espressione LINQ, ci sarà SelectMany. Ma sembra che il compilatore C # scelga solo la seconda firma. La prima firma non viene mai utilizzata.

        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);
        }

Con l'aiuto di Reflector, posso vedere che l'espressione LINQ sopra è tradotta in

en1.SelectMany<int, double, string>(delegate (int i1) {
        return en2;
    }, delegate (int i1, double i2) {
        double CS
        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;
    })
= i1 * i2return CS<*><*>.ToString(); })

L'esempio sopra riguarda 3 tipi. Pertanto, è ragionevole selezionare la seconda firma SelectMany. Tuttavia, per esempio di seguito, è coinvolto solo un tipo, seleziona comunque la seconda firma.

<*>

È tradotto in:

<*>

Quindi, non riesco a trovare un caso in cui l'espressione LINQ sia tradotta nella prima firma SelectMany. Esiste un caso del genere?

Se la prima firma SelectMany non viene utilizzata, esiste solo perché è BIND di monade nella programmazione funzionale?

Forse la domanda può essere: perché abbiamo 2 firme di SelectMany?

Grazie.

È stato utile?

Soluzione

Secondo le specifiche C #, il compilatore non genererà una chiamata di sovraccarico alla prima versione di SelectMany. La prima versione di SelectMany è utile per appiattire un elenco di elenchi in un unico elenco piatto.

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

Non ha un equivalente forte in un'espressione di query.

Per ulteriori informazioni, consultare la Sezione 7.15.2 delle specifiche del linguaggio C #.

Altri suggerimenti

  

perché abbiamo 2 firme di SelectMany?

Quindi posso usare il primo nel mio codice.

var orders = Customers.SelectMany(c => c.Orders)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top