El operador condicional nulo C#6 no funciona para la consulta LINQ
roslyn (1)
Esperaba que esto funcionara, pero aparentemente, la forma en que se genera el IL, NullReferenceException
. ¿Por qué el compilador no puede generar un código similar para las consultas?
En el caso de ThisWorks
, el compilador genera código que provoca un cortocircuito en el resto de la expresión, ¿por qué no puede hacer lo mismo para el caso de consulta LINQ?
class Target
{
public ChildTarget Child;
}
class ChildTarget
{
public int[] Values;
}
IEnumerable<int> ThisWorks(Target target) =>
target.Child?.Values.Select(x => x);
IEnumerable<int> ThisDoesNotWork(Target target) =>
from x in target.Child?.Values select x;
ThisWorks(new Target());
ThisDoesNotWork(new Target()); // this throws NullReferenceException
Resultados descompilados
private static IEnumerable<int> ThisDoesNotWork(Target target)
{
ChildTarget child = target.Child;
IEnumerable<int> values = (child != null) ? child.Values : null;
Func<int, int> func;
if ((func = Program._func) == null)
{
func = (Program._func = new Func<int, int>(Program._funcMethod));
}
return values.Select(func);
}
private static IEnumerable<int> ThisWorks(Target target)
{
ChildTarget child = target.Child;
IEnumerable<int> values;
if (child == null)
{
values = null;
}
else
{
IEnumerable<int> values = child.Values;
Func<int, int> func;
if ((func = Program._func2) == null)
{
func = (Program._func2= new Func<int, int>(Program._funcMethod2));
}
values = values.Select(func);
}
return values;
}
La respuesta está en la especificación del lenguaje C #, que dice
Una expresión de consulta de la forma.
de x en e selecciona x
se traduce a
( e ). Seleccione ( x => x )
Note los paréntesis alrededor de e en la última línea. Eso muestra claramente que la expresión condicional nula (en su ejemplo) termina antes de que se llame a Select, lo que significa que se podría llamar a Select con el nulo resultante.
¿Por qué no puede hacer lo mismo para Linq? Porque esa no es la forma en que la característica fue diseñada para trabajar. La especificación para los operadores condicionales nulos no tiene un caso especial para consultas, ni viceversa.