Mengapa saya tidak dapat menggunakan operator propagasi null dalam ekspresi lambda?

102

Saya sering menggunakan operator penyebaran null dalam kode saya karena memberi saya kode yang lebih mudah dibaca, khususnya dalam kueri yang panjang, saya tidak perlu memeriksa null setiap kelas yang digunakan.

Kode berikut memunculkan kesalahan kompilasi bahwa kita tidak dapat menggunakan operator propagasi null di lambda.

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

Kesalahannya:

Kesalahan CS8072 Pohon ekspresi lambda mungkin tidak berisi operator menyebarkan null.

C # Dapat dengan mudah menerjemahkan kode di atas ke kode ke kode berikut jika benar-benar tidak dapat melakukan hal lain!

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

Saya penasaran mengapa C # tidak melakukan apa-apa dan hanya menampilkan kesalahan kompiler?

Mohsen Sarkar
sumber
4
Foo?.Bartidak sama dengan Foo != null ? Foo.Bar : nullkarena Foodievaluasi sekali dengan operator penyebar null, dan dua kali dengan kondisional, sehingga terjemahan tidak akan benar di semua kasus.
Lucas Trzesniewski
3
Perhatikan bahwa jika kodenya untuk EF, ada kemungkinan bahwa Anda tidak benar-benar memerlukan operator penyebaran null, karena ketika kueri diubah ke panggilan SQL, SQL tidak membuang nulls :-)
xanatos
NB: Akan berguna juga untuk menulis 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)"};daripada harus menulis ProductName = (p == null) ? "(No products)" : p.ProductNamekarena EF saat ini tidak mendukung ?.operator.
Matt

Jawaban:

72

Ini rumit karena lambda pohon ekspresi (tidak seperti lambda delegasi) diinterpretasikan oleh penyedia LINQ yang sudah ada yang belum mendukung penyebaran null.

Mengonversi ke ekspresi kondisional tidak selalu akurat karena ada beberapa evaluasi sementara ?.hanya ada satu evaluasi misalnya:

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

Anda dapat pergi lebih dalam terkait pembahasan CodePlex mana 3 solusi yang ditawarkan: NullPropagationExpression, ConditionalExpression& hibrida

i3arnon
sumber
23
Saya pasti tidak akan terkejut jika penyedia kueri tertentu tidak dapat mendukungnya, tetapi itu bukan alasan untuk tidak mendukung bahasa C #.
Pelayanan
16
Fakta bahwa tertentu penyedia permintaan belum mendukung itu bukan alasan untuk melarang semua penyedia query dari yang pernah bisa menggunakannya.
Pelayanan
10
Dan jelas tidak ada penyedia kueri yang akan meluangkan waktu untuk mendukung penanganan permintaan semacam itu sampai pengguna penyedia tersebut dapat benar-benar membuat pohon ekspresi yang mewakilinya. Untuk mendukung hal ini, hal pertama yang perlu terjadi adalah lambda dapat mewakilinya. Setelah itu ada, penyedia kueri dapat mulai mendukungnya, karena mereka merasa itu sesuai. Ada juga banyak penyedia di luar sana yang melakukan berbagai hal berbeda. EF bukanlah satu-satunya penyedia kueri di dunia.
Pelayanan
7
Seluruh titik dari Expressionadalah untuk dapat mewakili semua C # ekspresi semantik sebagai kode. Ini tidak dirancang hanya untuk sebagian kecil dari bahasa.
Pelayanan
6
Sepertinya ini masih belum terselesaikan 3 tahun kemudian - bukankah seharusnya Microsoft dapat menemukan waktu sekarang? Mereka tampaknya memiliki kebiasaan buruk menggunakan waktu dan sumber daya sebagai alasan untuk setengah menerapkan fitur baru di C # hari ini.
NetMage