Tại sao tôi không thể sử dụng toán tử lan truyền null trong biểu thức lambda?


102

Tôi thường sử dụng toán tử lan truyền null trong mã của mình vì nó mang lại cho tôi mã dễ đọc hơn, đặc biệt trong các truy vấn dài, tôi không phải kiểm tra null từng lớp đơn lẻ được sử dụng.

Đoạn mã sau đưa ra một lỗi biên dịch mà chúng tôi không thể sử dụng toán tử lan truyền null trong lambda.

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

Lỗi :

Lỗi CS8072 Một lambda cây biểu thức có thể không chứa toán tử lan truyền rỗng.

C # có thể dễ dàng dịch mã ở trên sang mã sang mã sau nếu thực sự không thể làm gì khác!

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

Tôi tò mò tại sao C # không làm gì cả và chỉ đơn giản là ném một lỗi trình biên dịch?


4
Foo?.Barkhông tương đương với Foo != null ? Foo.Bar : nullFoođược đánh giá một lần với toán tử lan truyền null và hai lần với điều kiện, vì vậy bản dịch sẽ không chính xác trong mọi trường hợp.
Lucas Trzesniewski

3
Lưu ý rằng nếu mã của nó cho EF, có khả năng mà bạn không thực sự cần các nhà điều hành tuyên truyền null, bởi vì khi một truy vấn được chuyển thành SQL cuộc gọi, SQL không ném null :-)
xanatos

NB: Nó cũng sẽ hữu ích khi viết 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)"};thay vì phải viết ProductName = (p == null) ? "(No products)" : p.ProductNamevì EF hiện không hỗ trợ ?.toán tử.
Matt

Câu trả lời:


72

Nó phức tạp vì lambdas cây biểu thức (không giống lambdas đại biểu) được thông dịch bởi các nhà cung cấp LINQ hiện có chưa hỗ trợ việc truyền null.

Việc chuyển đổi thành một biểu thức có điều kiện không phải lúc nào cũng chính xác vì có nhiều đánh giá trong khi ?.chỉ có một đánh giá duy nhất, ví dụ:

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

Bạn có thể đi sâu hơn trong liên quan thảo luận trên CodePlex nơi 3 giải pháp được cung cấp: NullPropagationExpression, ConditionalExpression& một lai


23
Tôi chắc chắn sẽ không ngạc nhiên nếu một số nhà cung cấp truy vấn nhất định không thể hỗ trợ nó, nhưng đó không phải là lý do để không có ngôn ngữ C # hỗ trợ nó.
Servy

16
Thực tế là một số nhà cung cấp truy vấn vẫn chưa hỗ trợ nó không phải là một lý do để cấm tất cả các nhà cung cấp truy vấn từ bao giờ việc có thể sử dụng nó.
Servy

10
Và rõ ràng là sẽ không có nhà cung cấp truy vấn nào dành thời gian để hỗ trợ xử lý một yêu cầu như vậy cho đến khi người dùng của nhà cung cấp đó thực sự có thể tạo cây biểu thức đại diện cho nó. Để điều này được hỗ trợ, điều đầu tiên cần phải xảy ra là lambdas có thể đại diện cho nó. Sau khi tồn tại, các nhà cung cấp truy vấn có thể bắt đầu hỗ trợ nó, khi họ cảm thấy nó phù hợp. Ngoài ra còn có rất nhiều nhà cung cấp đang làm tất cả những việc khác nhau. Nó không giống như EF là nhà cung cấp truy vấn duy nhất trên thế giới.
Servy

7
Toàn bộ điểm của Expressionlà để có thể đại diện cho tất cả các C # biểu ngữ nghĩa như mã. Nó không được thiết kế để chỉ là một tập hợp con nhỏ của ngôn ngữ.
Servy

6
Có vẻ như điều này vẫn chưa được giải quyết 3 năm sau - lẽ ra Microsoft đã không thể tìm ra thời gian cho đến bây giờ? Họ dường như có thói quen xấu là sử dụng thời gian và tài nguyên như một cái cớ để triển khai một nửa các tính năng mới trong C # ngày nay.
NetMage
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.