¿Por qué no puedo usar el operador de propagación nula en expresiones lambda?

102

A menudo uso un operador de propagación nulo en mi código porque me da un código más legible, especialmente en consultas largas, no tengo que verificar cada clase que se usa.

El siguiente código arroja un error de compilación que no podemos usar un operador de propagación nulo en lambda.

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

El error :

Error CS8072 Una lambda de árbol de expresión no puede contener un operador de propagación nulo.

C # ¡Podría traducir fácilmente el código anterior al código siguiente si realmente no puede hacer nada más!

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

Tengo curiosidad por saber por qué C # no hace nada y simplemente arroja un error del compilador.

Mohsen Sarkar
fuente
4
Foo?.Barno es equivalente a Foo != null ? Foo.Bar : nullporque Foose evalúa una vez con el operador de propagación nula y dos veces con el condicional, por lo que la traducción no sería correcta en todos los casos.
Lucas Trzesniewski
3
Tenga en cuenta que si es código para EF, existe la posibilidad de que realmente no necesite el operador de propagación de nulos, porque cuando una consulta se convierte a una llamada SQL, SQL no arroja nulos :-)
xanatos
NB: También sería útil escribir en 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)"};lugar de tener que escribir ProductName = (p == null) ? "(No products)" : p.ProductNameporque EF actualmente no admite el ?.operador.
Matt

Respuestas:

72

Es complicado ya que las lambdas del árbol de expresión (a diferencia de las lambdas delegadas) son interpretadas por proveedores LINQ ya existentes que aún no admiten la propagación nula.

La conversión a una expresión condicional no siempre es precisa, ya que hay varias evaluaciones, mientras que con ?.solo hay una única evaluación, por ejemplo:

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

Usted puede ir más profundo en el correspondiente debate en CodePlex , donde hay 3 soluciones: NullPropagationExpression, ConditionalExpressiony un híbrido

i3arnon
fuente
23
Ciertamente no me sorprendería si ciertos proveedores de consultas no pudieran admitirlo, pero esa no es una razón para que el lenguaje C # no lo admita.
Servicio
16
El hecho de que ciertos proveedores de consulta todavía no lo soportan no es una razón para prohibir todos los proveedores de consulta de cada vez ser capaz de utilizarlo.
Servicio
10
Y, obviamente, ningún proveedor de consultas se tomará el tiempo para admitir el manejo de dicha solicitud hasta que los usuarios de ese proveedor puedan crear árboles de expresión que la representen. Para que esto sea compatible, lo primero que debe suceder es que las lambdas puedan representarlo. Una vez que existe, los proveedores de consultas pueden comenzar a admitirlo, según lo consideren apropiado. También hay muchos proveedores que hacen todo tipo de cosas diferentes. No es que EF sea el único proveedor de consultas del mundo.
Servicio
7
El objetivo de Expressiones poder representar todas las expresiones de C # semánticamente como código. No está diseñado para ser solo un pequeño subconjunto del lenguaje.
Servicio
6
Parece que esto todavía no se resuelve 3 años después, ¿no debería Microsoft haber podido encontrar el tiempo ahora? Parece que tienen la mala costumbre de utilizar el tiempo y los recursos como excusa para la mitad de la implementación de nuevas características en C # en estos días.
NetMage