2016-03-09 18 views
16

Tôi mong đợi điều này để làm việc, nhưng dường như cách IL tạo ra, nó ném NullReferenceException. Tại sao trình biên dịch không thể tạo ra mã tương tự cho các truy vấn?C# 6 null toán tử điều kiện không hoạt động cho truy vấn LINQ

Trong trường hợp ThisWorks, trình biên dịch tạo mã ngắn mạch phần còn lại của biểu thức, tại sao nó không thể làm điều tương tự cho trường hợp truy vấn 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 

decompiled quả

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; 
} 
+0

Tôi đoán là trình biên dịch dịch toán tử điều kiện null trước tiên trước khi dịch cú pháp truy vấn. Vì vậy, truy vấn của bạn giống như '(Child == null? Null: Child.Values) .Select (x => x)'. Nếu nó đã dịch cú pháp truy vấn sang cú pháp phương thức đầu tiên thì nó sẽ hoạt động. – juharr

+0

Tại sao bạn mong đợi nó hoạt động khác? Trong ví dụ của bạn, 'target.Child? .Values' đánh giá thành' null'. Null có điều kiện chỉ ảnh hưởng đến biểu thức nó là một phần của. Bạn đang thực hiện một cách hiệu quả 'null.Select (...)'. –

+0

@JeffMercado Tôi mong đợi 'từ x trong e? .Value chọn x' là' e? .Value.Select (x = x>) '* vì * biểu thức sau * hoạt động * đây là sự ngạc nhiên. Như @Neal đã chỉ ra, đó là khung giá tinh tế để đổ lỗi, cũng như thứ tự biến đổi quá –

Trả lời

9

Câu trả lời là trong C# ngôn ngữ đặc tả, mà nói

Một biểu thức truy vấn có dạng

từ x trong e chọn x

được dịch sang

(e). Chọn (x =>x)

Note ngoặc xung quanh e trong dòng cuối cùng. Điều đó cho thấy rõ ràng rằng biểu thức null có điều kiện (trong ví dụ của bạn) kết thúc trước khi Select được gọi, có nghĩa là Select có thể được gọi với null kết quả.

Tại sao nó không thể làm điều tương tự cho LINQ? Bởi vì đó không phải là cách tính năng được thiết kế để hoạt động. Đặc điểm kỹ thuật cho các toán tử null có điều kiện không có trường hợp đặc biệt cho các truy vấn, và ngược lại.

+0

Tôi đã lên kế hoạch tìm kiếm đặc điểm kỹ thuật cho toán tử điều kiện rỗng để hoàn thành giải thích này, chỉ để tìm thấy không có gì. Bây giờ sẽ phải dành thời gian phân tích cú pháp luồng này để tìm ra điều gì đã xảy ra: https://roslyn.codeplex.com/discussions/540883 –

+0

Cũng xác nhận điều này '(target.Child? .Values) .Select (x => x) 'cũng ném, như mong đợi. –

Các vấn đề liên quan