สายเกินไปที่จะเพิ่มคำตอบอีกหรือไม่
ฉันเขียนโค้ด LINQ-to-object จำนวนมากและฉันยืนยันว่าอย่างน้อยในโดเมนนั้นที่ดีที่จะเข้าใจไวยากรณ์ทั้งสองเพื่อที่จะใช้สิ่งใดก็ตามที่ทำให้โค้ดง่ายขึ้น - ซึ่งไม่ใช่จุดแบบไวยากรณ์เสมอไป
แน่นอนว่ามีบางครั้งที่ dot-syntax IS เป็นทางไป - คนอื่น ๆ ได้ให้หลายกรณี อย่างไรก็ตามฉันคิดว่าความเข้าใจมีการเปลี่ยนแปลงสั้น ๆ - ถ้าคุณจะแร็พ ดังนั้นฉันจะให้ตัวอย่างที่ฉันเชื่อว่าความเข้าใจมีประโยชน์
ต่อไปนี้เป็นวิธีแก้ปริศนาการแทนที่ตัวเลข: (โซลูชันที่เขียนโดยใช้ LINQPad แต่สามารถทำงานแบบสแตนด์อโลนในแอปคอนโซล)
// NO
// NO
// NO
//+NO
//===
// OK
var solutions =
from O in Enumerable.Range(1, 8) // 1-9
//.AsQueryable()
from N in Enumerable.Range(1, 8) // 1-9
where O != N
let NO = 10 * N + O
let product = 4 * NO
where product < 100
let K = product % 10
where K != O && K != N && product / 10 == O
select new { N, O, K };
foreach(var i in solutions)
{
Console.WriteLine("N = {0}, O = {1}, K = {2}", i.N, i.O, i.K);
}
//Console.WriteLine("\nsolution expression tree\n" + solutions.Expression);
... ผลลัพธ์ใด:
N = 1, O = 6, K = 4
ไม่เลวร้ายเกินไปตรรกะไหลเป็นเส้นตรงและเราจะเห็นว่ามันเกิดขึ้นด้วยวิธีการแก้ไขที่ถูกต้องเพียงครั้งเดียว ปริศนานี้ง่ายต่อการแก้ด้วยมือ: ให้เหตุผลว่า 3>> N
0 และO
> 4 * N บอกเป็นนัย 8> = O
> = 4 นั่นหมายความว่ามี 10 กรณีทดสอบด้วยมือสูงสุด (2 สำหรับN
-by- 5 สำหรับO
) ฉันหลงทางมากพอ - ปริศนานี้มีให้เพื่อใช้เป็นภาพประกอบของ LINQ
การแปลงคอมไพเลอร์
มีหลายคอมไพเลอร์ทำเพื่อแปลสิ่งนี้เป็น dot-syntax ที่เทียบเท่ากัน นอกจากนี้ตามปกติสองและต่อมาfrom
คำสั่งได้รับกลายเป็นSelectMany
สายที่เรามีlet
ข้อที่จะกลายเป็นSelect
สายที่มีการคาดการณ์ซึ่งทั้งสองใช้โปร่งใสตัวระบุ ในขณะที่ฉันกำลังจะแสดงการต้องตั้งชื่อตัวระบุเหล่านี้ในรูปแบบของจุดจะห่างจากความสามารถในการอ่านของวิธีการนั้น
ฉันมีเคล็ดลับสำหรับการเปิดเผยสิ่งที่คอมไพเลอร์ทำในการแปลรหัสนี้เป็นรูปแบบจุด หากคุณไม่ใส่เครื่องหมายข้อคิดเห็นทั้งสองบรรทัดด้านบนและเรียกใช้อีกครั้งคุณจะได้รับผลลัพธ์ต่อไปนี้:
N = 1, O = 6, K = 4
แผนผังนิพจน์โซลูชัน System.Linq.Enumerable + d_ b8.SelectMany (O => ช่วง (1, 8), (O, N) => ใหม่ <> f _AnonymousType0 2(O = O, N = N)).Where(<>h__TransparentIdentifier0 => (<>h__TransparentIdentifier0.O != <>h__TransparentIdentifier0.N)).Select(<>h__TransparentIdentifier0 => new <>f__AnonymousType1
2 (<> h_ TransparentIdentifier0 = NO > h _TransparentIdentifier0, NO = ((10 * <> h_ TransparentIdentifier0.N) + <> h _TransparentIdentifier0.O))) เลือก (<> h_ TransparentIdentifier1 => ใหม่ <> f _AnonymousType2 2(<>h__TransparentIdentifier1 = <>h__TransparentIdentifier1, product = (4 * <>h__TransparentIdentifier1.NO))).Where(<>h__TransparentIdentifier2 => (<>h__TransparentIdentifier2.product < 100)).Select(<>h__TransparentIdentifier2 => new <>f__AnonymousType3
2 (<> h_TransparentIdentifier2 = <> h _TransparentIdentifier2) <> h_ TransparentIdentifier2.product% 10))) โดยที่ (<> h _TransparentIdentifier3 => (((<> h_ TransparentIdentifier3.K! = <> h _TransparentIdentifier3. <> h_ TransparentIdentifier2h _TransparentIdentifier1. <> h_TransparentIdentifier0.O) andalso (<> H _TransparentIdentifier3.K! = <> h_ TransparentIdentifier3. <> H _TransparentIdentifier2. <> h_ TransparentIdentifier1. <> H _TransparentIdentifier0.N)) andalso ((<> h_ TransparentIdentifier3. <> H _TransparentIdentifier2 ผลิตภัณฑ์ / 10) == <> h_ TransparentIdentifier3. <> h _TransparentIdentifier2. <> h_ TransparentIdentifier1. <> h _TransparentIdentifier0.O)) เลือก (<> h_ TransparentIdentifier3 => ใหม่ <> f _AnonymousTypeifier4 > h_ TransparentIdentifier3. <> h _TransparentIdentifier2. <> h_ TransparentIdentifier1. <> h _TransparentIdentifier0.N,O = <> h_ TransparentIdentifier3. <> h_TransparentIdentifier2. <> h_ TransparentIdentifier1. <> h _TransparentIdentifier0.O, K = <> h__TransparentIdentifier3.K))
การใส่ตัวดำเนินการ LINQ แต่ละรายการในบรรทัดใหม่แปลตัวระบุ "ไม่สามารถบรรยายได้" เป็นตัวที่เราสามารถ "พูด" เปลี่ยนประเภทนิรนามให้อยู่ในรูปแบบที่คุ้นเคยและเปลี่ยนAndAlso
นิพจน์ต้นไม้ - ต้นไม้ศัพท์แสงเพื่อ&&
แสดงการเปลี่ยนแปลงที่คอมไพเลอร์ ในรูปแบบจุด:
var solutions =
Enumerable.Range(1,8) // from O in Enumerable.Range(1,8)
.SelectMany(O => Enumerable.Range(1, 8), (O, N) => new { O = O, N = N }) // from N in Enumerable.Range(1,8)
.Where(temp0 => temp0.O != temp0.N) // where O != N
.Select(temp0 => new { temp0 = temp0, NO = 10 * temp0.N + temp0.O }) // let NO = 10 * N + O
.Select(temp1 => new { temp1 = temp1, product = 4 * temp1.NO }) // let product = 4 * NO
.Where(temp2 => temp2.product < 100) // where product < 100
.Select(temp2 => new { temp2 = temp2, K = temp2.product % 10 }) // let K = product % 10
.Where(temp3 => temp3.K != temp3.temp2.temp1.temp0.O && temp3.K != temp3.temp2.temp1.temp0.N && temp3.temp2.product / 10 == temp3.temp2.temp1.temp0.O)
// where K != O && K != N && product / 10 == O
.Select(temp3 => new { N = temp3.temp2.temp1.temp0.N, O = temp3.temp2.temp1.temp0.O, K = temp3.K });
// select new { N, O, K };
foreach(var i in solutions)
{
Console.WriteLine("N = {0}, O = {1}, K = {2}", i.N, i.O, i.K);
}
ซึ่งถ้าคุณเรียกใช้คุณสามารถตรวจสอบว่ามันออกมาอีกครั้ง:
N = 1, O = 6, K = 4
... แต่คุณจะเขียนโค้ดแบบนี้หรือไม่?
ฉันพนันได้เลยว่าคำตอบคือ NONBHN (ไม่เพียง แต่ไม่เท่านั้น แต่ไม่มีนรก!) - เพราะมันซับซ้อนเกินไป แน่ใจว่าคุณสามารถสร้างชื่อตัวระบุที่มีความหมายได้มากกว่า "temp0" .. "temp3" แต่ประเด็นก็คือพวกเขาไม่ได้เพิ่มอะไรลงในรหัส - พวกเขาไม่ได้ทำให้โค้ดทำงานได้ดีขึ้น ทำให้โค้ดอ่านดีขึ้นพวกเขาน่าเกลียดแค่โค้ดและถ้าคุณทำมันด้วยมือไม่ต้องสงสัยเลยว่าคุณจะเลอะมันซักครั้งหรือสามครั้งก่อนจะทำให้ถูกต้อง นอกจากนี้การเล่น "เกมชื่อ" นั้นยากพอสำหรับตัวระบุที่มีความหมายดังนั้นฉันจึงยินดีต้อนรับตัวแบ่งจากเกมชื่อที่ผู้เรียบเรียงให้ฉันในแบบสอบถามความเข้าใจ
ตัวอย่างปริศนานี้อาจจะไม่เป็นจริงของโลกพอสำหรับคุณที่จะใช้อย่างจริงจัง อย่างไรก็ตามมีสถานการณ์อื่นที่มีความเข้าใจในการสืบค้นส่อง:
- ความซับซ้อนของ
Join
และGroupJoin
: การกำหนดขอบเขตของตัวแปรช่วงในjoin
อนุประโยคความเข้าใจแบบสอบถามเปลี่ยนความผิดพลาดที่อาจจะรวบรวมในรูปแบบจุดลงในข้อผิดพลาดรวบรวมเวลาในไวยากรณ์ความเข้าใจ
- เมื่อใดก็ตามที่คอมไพเลอร์จะแนะนำตัวระบุโปร่งใสในการแปลงความเข้าใจความเข้าใจจะคุ้มค่า ซึ่งรวมถึงการใช้ข้อใดข้อหนึ่งต่อไปนี้:
from
คำสั่งหลายข้อjoin
& join..into
ข้อและlet
ข้อ
ฉันรู้จักร้านวิศวกรรมมากกว่าหนึ่งแห่งในบ้านเกิดของฉันซึ่งมีไวยากรณ์ความเข้าใจที่ผิดกฎหมาย ฉันคิดว่านี่เป็นเรื่องที่น่าเสียดายเพราะความเข้าใจไวยากรณ์เป็นเพียงเครื่องมือและสิ่งที่มีประโยชน์ ฉันคิดว่ามันเหมือนพูดว่า"มีหลายสิ่งที่คุณสามารถทำได้ด้วยไขควงที่คุณไม่สามารถทำกับสิ่วได้เพราะคุณสามารถใช้ไขควงเป็นสิ่วสิ่วถูกแบนตั้งแต่นี้ไปภายใต้พระราชกฤษฎีกาของกษัตริย์"