Mi aspettavo che funzionasse, ma apparentemente il modo in cui l'IL genera, genera NullReferenceException
. Perché il compilatore non può generare un codice simile per le query?L'operatore condizionale nullo C# 6 non funziona per la query LINQ
Nel caso ThisWorks
, il compilatore genera codice che cortocircuita il resto dell'espressione, perché non può fare la stessa cosa per il caso di query 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
decompilato risultati
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 mia ipotesi è che il compilatore traduca l'operatore condizionale nullo prima di tradurre la sintassi della query. Quindi la tua query è come '(Child == null? Null: Child.Values) .Select (x => x)'. Se avesse tradotto la sintassi della query sulla sintassi del metodo prima avrebbe funzionato. – juharr
Perché ti aspetteresti che si comporti diversamente? Nel tuo esempio, 'target.Child? .Values' valuta a' null'. Il condizionale nullo influenza solo l'espressione di cui fa parte. Stai facendo effettivamente 'null.Select (...)'. –
@JeffMercado Mi aspetto 'da x in e? .Value selezionare x' per essere' e? .Value.Select (x = x>) '* poiché * l'espressione successiva * funziona * questa è la sorpresa. Come ha fatto notare @Neal, è la parentesi sottile a dare la colpa, così come l'ordine delle trasformazioni –