เหตุใดฉันจึงไม่สามารถใช้ตัวดำเนินการการขยายค่าว่างในนิพจน์แลมบ์ดาได้


104

ฉันมักจะใช้ตัวดำเนินการเผยแพร่ค่าว่างในโค้ดของฉันเพราะมันทำให้ฉันมีโค้ดที่อ่านได้ง่ายขึ้นโดยเฉพาะในการสืบค้นแบบยาวฉันไม่ต้องตรวจสอบค่า null ทุกคลาสที่ใช้

โค้ดต่อไปนี้แสดงข้อผิดพลาดในการคอมไพล์ที่เราไม่สามารถใช้ตัวดำเนินการโฆษณาแบบ null ในแลมบ์ดาได้

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

ความผิดพลาด :

ข้อผิดพลาด CS8072 แลมบ์ดาแผนผังนิพจน์อาจไม่มีตัวดำเนินการการเผยแพร่ค่าว่าง

C # สามารถแปลโค้ดด้านบนเป็นโค้ดเป็นโค้ดต่อไปนี้ได้อย่างง่ายดายหากทำอย่างอื่นไม่ได้!

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

ฉันสงสัยว่าทำไม C # ไม่ทำอะไรเลยและเพียงแค่แสดงข้อผิดพลาดของคอมไพเลอร์?


4
Foo?.Barไม่เทียบเท่ากับFoo != null ? Foo.Bar : nullเพราะFooถูกประเมินหนึ่งครั้งด้วยตัวดำเนินการเผยแพร่ค่าว่างและสองครั้งโดยใช้เงื่อนไขดังนั้นการแปลจะไม่ถูกต้องในทุกกรณี
Lucas Trzesniewski

3
โปรดทราบว่าหากรหัสของมันสำหรับ EF มีความเป็นไปได้ที่คุณไม่ต้องการตัวดำเนินการเผยแพร่ null เพราะเมื่อแบบสอบถามถูกแปลงเป็นการเรียก SQL SQL จะไม่ทิ้งค่าว่าง :-)
xanatos

หมายเหตุ:การเขียน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)"};แทนการเขียนจะเป็นประโยชน์เช่นกันProductName = (p == null) ? "(No products)" : p.ProductNameเพราะปัจจุบัน EF ไม่รองรับตัว?.ดำเนินการ
Matt

คำตอบ:


74

มีความซับซ้อนเนื่องจาก lambdas ต้นไม้นิพจน์ (ไม่เหมือนกับ lambdas ที่ได้รับมอบหมาย) ถูกตีความโดยผู้ให้บริการ LINQ ที่มีอยู่แล้วซึ่งยังไม่รองรับการแพร่กระจายแบบ null

การแปลงเป็นนิพจน์เงื่อนไขไม่ถูกต้องเสมอไปเนื่องจากมีการประเมินหลายครั้งในขณะที่?.มีเพียงการประเมินเดียวเช่น

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

คุณสามารถลงลึกในการอภิปรายที่เกี่ยวข้องเกี่ยวกับ CodePlexซึ่งมี 3 โซลูชัน: NullPropagationExpression, ConditionalExpression& ไฮบริด


26
ฉันจะไม่แปลกใจอย่างแน่นอนหากผู้ให้บริการสืบค้นบางรายไม่สามารถรองรับได้ แต่นั่นไม่ใช่เหตุผลที่จะไม่มีภาษา C # รองรับ
Servy

18
ความจริงที่ว่าบางผู้ให้บริการแบบสอบถามยังไม่สนับสนุนมันไม่ได้เป็นเหตุผลที่จะห้ามทุกผู้ให้บริการแบบสอบถามจากที่เคยความสามารถในการใช้งานได้
Servy

11
และเห็นได้ชัดว่าไม่มีผู้ให้บริการสืบค้นรายใดใช้เวลาในการสนับสนุนการจัดการคำขอดังกล่าวจนกว่าผู้ใช้ของผู้ให้บริการรายนั้นจะสามารถสร้างแผนภูมินิพจน์ที่เป็นตัวแทนได้จริง เพื่อให้ได้รับการสนับสนุนสิ่งแรกที่ต้องเกิดขึ้นคือ lambdas สามารถเป็นตัวแทนได้ หลังจากนั้นผู้ให้บริการแบบสอบถามสามารถเริ่มให้การสนับสนุนได้ตามที่เห็นว่าเหมาะสม นอกจากนี้ยังมีผู้ให้บริการมากมายที่ทำสิ่งต่าง ๆ มากมาย ไม่ใช่ว่า EF เป็นเพียงผู้ให้บริการสืบค้นข้อมูลรายเดียวในโลก
Servy

8
ทั้งประเด็นของการExpressionที่จะสามารถที่จะเป็นตัวแทนของทุกการแสดงออก C # ความหมายเป็นรหัส ไม่ได้ออกแบบมาให้เป็นเพียงส่วนย่อยของภาษา
Servy

7
ดูเหมือนว่าสิ่งนี้จะยังไม่ได้รับการแก้ไขในอีก 3 ปีต่อมาไมโครซอฟท์ไม่สามารถหาเวลาได้หรือไม่? ดูเหมือนพวกเขาจะมีนิสัยที่ไม่ดีในการใช้เวลาและทรัพยากรเป็นข้ออ้างในการใช้งานคุณลักษณะใหม่ ๆ ใน C # ในปัจจุบัน
NetMage
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.