Warum kann ich den Null-Propagationsoperator nicht in Lambda-Ausdrücken verwenden?

101

Ich verwende häufig einen Null-Propagierungsoperator in meinem Code, weil er mir besser lesbaren Code bietet, insbesondere bei langen Abfragen, bei denen ich nicht jede einzelne verwendete Klasse auf Null prüfen muss.

Der folgende Code löst einen Kompilierungsfehler aus, für den in Lambda kein Null-Propagierungsoperator verwendet werden kann.

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

Der Fehler :

Fehler CS8072 Ein Ausdrucksbaum-Lambda enthält möglicherweise keinen Null-Propagierungsoperator.

C # Könnte den obigen Code leicht in den Code in den folgenden Code übersetzen, wenn wirklich nichts anderes möglich ist!

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

Ich bin gespannt, warum C # nichts tut und einfach einen Compilerfehler auslöst.

Mohsen Sarkar
quelle
4
Foo?.Barist nicht gleichbedeutend mit, Foo != null ? Foo.Bar : nullda Fooeinmal mit dem sich null ausbreitenden Operator und zweimal mit der Bedingung ausgewertet wird, sodass die Übersetzung nicht in allen Fällen korrekt wäre.
Lucas Trzesniewski
3
Beachten Sie, dass es bei seinem Code für EF die Möglichkeit gibt, dass Sie den Null-Propagierungsoperator nicht wirklich benötigen, da SQL bei der Konvertierung einer Abfrage in einen SQL-Aufruf keine Nullen auslöst :-)
xanatos
NB: Es wäre auch nützlich zu schreiben, 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)"};anstatt schreiben zu müssen, ProductName = (p == null) ? "(No products)" : p.ProductNameda EF den ?.Operator derzeit nicht unterstützt .
Matt

Antworten:

71

Dies ist kompliziert, da Ausdrucksbaum-Lambdas (im Gegensatz zu delegierten Lambdas) von bereits vorhandenen LINQ-Anbietern interpretiert werden, die die Null-Weitergabe noch nicht unterstützen.

Die Konvertierung in einen bedingten Ausdruck ist nicht immer korrekt, da mehrere Auswertungen vorliegen, während ?.nur eine einzige Auswertung vorliegt, zum Beispiel:

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

Sie können in der jeweiligen tiefe Diskussion auf CodePlex , wo drei Lösungen angeboten: NullPropagationExpression, ConditionalExpression& a hybrid

i3arnon
quelle
23
Es würde mich sicherlich nicht wundern, wenn bestimmte Abfrageanbieter dies nicht unterstützen könnten, aber das ist kein Grund, warum die C # -Sprache dies nicht unterstützt.
Servy
16
Die Tatsache, dass bestimmte Abfrageanbieter dies noch nicht unterstützen, ist kein Grund, allen Abfrageanbietern zu verbieten, es jemals verwenden zu können.
Servy
10
Und offensichtlich wird sich kein Abfrageanbieter die Zeit nehmen, die Bearbeitung einer solchen Anfrage zu unterstützen, bis Benutzer dieses Anbieters tatsächlich Ausdrucksbäume erstellen können, die sie darstellen. Damit dies unterstützt wird, muss das erste, was passieren muss, dass Lambdas es darstellen können. Nachdem dies vorhanden ist, können Abfrageanbieter damit beginnen , es zu unterstützen, wenn sie dies für angemessen halten. Es gibt auch viele Anbieter, die alle möglichen Dinge tun. Es ist nicht so, dass EF der einzige Abfrageanbieter der Welt ist.
Servy
7
Der ganze Punkt der Expressionist in der Lage sein , alle Ausdrücke C # semantisch als Code darzustellen. Es ist nicht nur eine kleine Teilmenge der Sprache.
Servy
6
Scheint, als ob dies 3 Jahre später immer noch nicht gelöst ist - hätte Microsoft die Zeit nicht schon finden können? Sie scheinen die schlechte Angewohnheit zu haben, Zeit und Ressourcen als Ausrede für die halbe Implementierung neuer Funktionen in C # zu verwenden.
NetMage