Spodziewałem się, że to zadziała, ale najwyraźniej sposób, w jaki generuje IL, rzuca NullReferenceException
. Dlaczego kompilator nie może wygenerować podobnego kodu dla zapytań?C# 6 null operator warunkowy nie działa dla zapytania LINQ
W przypadku ThisWorks
kompilator generuje kod, który powoduje zwarcie reszty wyrażenia, dlaczego nie może zrobić tego samego dla przypadku zapytania 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
dekompilowana wyniki
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;
}
Domyślam się, że kompilator tłumaczy najpierw operator warunkowy o wartości null, zanim przetłumaczy składnię zapytania. Więc twoje zapytanie jest podobne do '(Child == null? Null: Child.Values). Wybierz (x => x)'. Gdyby najpierw przetłumaczył składnię zapytania na składnię metody, zadziałałoby. – juharr
Dlaczego miałbyś się spodziewać, że zachowa się inaczej? W twoim przykładzie parametr 'target.Child? .Values' zwraca wartość' null'. Warunek zerowy ma wpływ tylko na wyrażenie, którego jest częścią. Skutecznie robisz 'null.Select (...)'. –
@JeffMercado Spodziewam się, że 'od x w e? .Wartość wybierz x' to' e? .Wartość.Wybierz (x = x>) '* od * późniejsze wyrażenie * działa * to jest niespodzianka. Jak zaznaczył @Neal, to subtelny bracketing jest winien, a także kolejność transformacji. –