Perché non posso utilizzare l'operatore di propagazione null nelle espressioni lambda?


102

Uso spesso l'operatore di propagazione nullo nel mio codice perché mi dà un codice più leggibile, specialmente nelle query lunghe non devo controllare nullo ogni singola classe che viene utilizzata.

Il codice seguente genera un errore di compilazione che non è possibile utilizzare l'operatore di propagazione null in lambda.

var cnt = humans.AsQueryable().Count(a => a.House?[0].Price == 5000);

L'errore :

Errore CS8072 Un lambda della struttura ad albero delle espressioni potrebbe non contenere un operatore di propagazione nullo.

C # Potrebbe facilmente tradurre il codice sopra nel codice nel codice seguente se davvero non puoi fare nient'altro!

var cnt = humans.AsQueryable().Count(a => a.House != null && a.House[0].Price == 5000);

Sono curioso del motivo per cui C # non fa nulla e genera semplicemente un errore del compilatore?


4
Foo?.Barnon è equivalente a Foo != null ? Foo.Bar : nullperché Fooviene valutato una volta con l'operatore di propagazione null e due volte con il condizionale, quindi la traduzione non sarebbe corretta in tutti i casi.
Lucas Trzesniewski

3
Nota che se il suo codice per EF, c'è la possibilità che tu non abbia davvero bisogno dell'operatore di propagazione null, perché quando una query viene convertita in chiamata SQL, SQL non genera null :-)
xanatos

NB: Sarebbe anche utile scrivere var q = from c in Categories join p in Products on c equals p.Category into ps from p in ps.DefaultIfEmpty() select new { Category = c, ProductName = (p?.ProductName)??"(No products)"};invece di dover scrivere ProductName = (p == null) ? "(No products)" : p.ProductNameperché EF attualmente non supporta l' ?.operatore.
Matt

Risposte:


72

È complicato poiché le espressioni lambda dell'albero delle espressioni (a differenza delle espressioni lambda delegate) vengono interpretate da provider LINQ già esistenti che non supportano ancora la propagazione null.

La conversione in un'espressione condizionale non è sempre accurata in quanto ci sono più valutazioni mentre con ?.c'è solo una valutazione, ad esempio:

customer.Where(a => c.Increment()?.Name) // Written by the user 
customer.Where(a => c.Increment() == null ? null : c.Increment().Name) // Incorrectly interpreted by an old LINQ provider

Si può andare più a fondo nella relativa discussione su CodePlex , dove sono offerti 3 soluzioni: NullPropagationExpression, ConditionalExpressione un ibrido


23
Certamente non sarei sorpreso se alcuni provider di query non potessero supportarlo, ma non è un motivo per cui il linguaggio C # non lo supporta.
Servizio

16
Il fatto che alcuni fornitori di query ancora non supportano non è un motivo per vietare tutti i fornitori di query da mai essere in grado di usarlo.
Servizio

10
E ovviamente nessun provider di query si prenderà il tempo per supportare la gestione di tale richiesta fino a quando gli utenti di quel provider non saranno in grado di creare effettivamente alberi di espressione che lo rappresentino. Affinché questo sia supportato, la prima cosa che deve accadere è che i lambda siano in grado di rappresentarlo. Dopo che esiste, i provider di query possono iniziare a supportarlo, se lo ritengono appropriato. Ci sono anche molti fornitori là fuori che fanno ogni sorta di cose diverse. Non è che EF sia l'unico provider di query al mondo.
Servizio

7
L'intero punto di Expressionè quello di essere in grado di rappresentare tutte le espressioni C # semanticamente come codice. Non è progettato per essere solo un piccolo sottoinsieme della lingua.
Servizio

6
Sembra che questo non sia ancora risolto 3 anni dopo: Microsoft non avrebbe dovuto essere in grado di trovare il tempo ormai? Sembra che abbiano la cattiva abitudine di usare tempo e risorse come scusa per implementare a metà le nuove funzionalità in C # in questi giorni.
NetMage
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.