Apakah sudah terlambat untuk menambahkan jawaban lain?
Saya telah menulis satu ton kode LINQ-to-objek dan saya berpendapat bahwa setidaknya dalam domain itu ada baiknya untuk memahami kedua sintaks untuk menggunakan mana saja yang membuat kode lebih sederhana - yang tidak selalu dot-sintaks.
Tentu saja ada saat-saat ketika sintaksis ADALAH cara untuk pergi - yang lain telah menyediakan beberapa kasus ini; namun, saya pikir pemahamannya telah diubah - diberikan rap yang buruk, jika Anda mau. Jadi saya akan memberikan sampel di mana saya percaya pemahaman berguna.
Inilah solusi untuk puzzle substitusi digit: (solusi ditulis menggunakan LINQPad, tetapi dapat berdiri sendiri di aplikasi konsol)
// 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);
... yang keluaran:
N = 1, O = 6, K = 4
Tidak terlalu buruk, logika mengalir secara linier dan kita dapat melihat bahwa ia muncul dengan solusi tunggal yang benar. Teka-teki ini cukup mudah untuk diselesaikan dengan tangan: dengan alasan bahwa 3>> N
0, dan O
> 4 * N menyiratkan 8> = O
> = 4. Itu berarti ada maksimal 10 kasus untuk diuji dengan tangan (2 untuk-oleh- N
5 untuk O
). Saya sudah cukup tersesat - puzzle ini ditawarkan untuk tujuan ilustrasi LINQ.
Transformasi Kompiler
Ada banyak yang dilakukan kompiler untuk menerjemahkannya ke dalam sintaks dot-ekuivalen. Selain klausa kedua dan selanjutnya yangfrom
SelectMany
biasa diubah menjadi panggilan, kami memiliki let
klausa yang menjadi Select
panggilan dengan proyeksi, keduanya menggunakan pengidentifikasi transparan . Seperti yang akan saya tunjukkan, harus menyebutkan nama pengidentifikasi ini dalam dot-sintaks menghilangkan dari keterbacaan pendekatan itu.
Saya punya trik untuk mengekspos apa yang dilakukan kompiler dalam menerjemahkan kode ini ke sintaks dot. Jika Anda menghapus komentar dari dua baris yang dikomentari di atas dan menjalankannya lagi, Anda akan mendapatkan output berikut:
N = 1, O = 6, K = 4
pohon solusi ekspresi System.Linq.Enumerable + d_ b8.SelectMany (O => Range (1, 8), (O, N) => baru <> 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 = <> h _TransparentIdentifier0, NO = ((10 * <> h_ TransparentIdentifier0.N) + <> h _TransparentIdentifier0.O))). Pilih (<> h_ TransparentIdentifier1 => baru <> 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, K = ( <> h_ TransparentIdentifier2.product% 10))). Di mana (<> h _TransparentIdentifier3 => (((<<h_ TransparentIdentifier3.K! = <> h _TransparentIdentifier3. <> h_ TransparentIdentifier2. <>h _TransparentIdentifier1. <> h_TransparentIdentifier0.O) AndAlso (<> h _TransparentIdentifier3.K! = <> H_ TransparentIdentifier3. <> H _TransparentIdentifier2. <> H_TransparentIdentifier1 . <> H _TransparentIdentifier0.N)) DanAlso ((<html) Transparansi . produk / 10) == <> h_ TransparentIdentifier3. <> h _TransparentIdentifier2. <> h_ TransparentIdentifier1. <> h _TransparentIdentifier0.O))). Pilih (<> h_ TransparentIdentifier3 => new <> f _AnonymousType4`3 (N = < > h_ TransparentIdentifier3. <> h _TransparentIdentifier2. <> h_ TransparentIdentifier1. <> h _TransparentIdentifier0.N,O = <> h_ TransparentIdentifier3. <> H_TransparentIdentifier2. <> H_ TransparentIdentifier1. <> H _TransparentIdentifier0.O, K = <> h__TransparentIdentifier3.K))
Menempatkan setiap operator LINQ pada baris baru, menerjemahkan pengidentifikasi "tak terkatakan" ke yang kita bisa "berbicara", mengubah tipe anonim ke bentuk yang mereka kenal dan mengubah AndAlso
istilah pohon ekspresi untuk &&
memaparkan transformasi yang dilakukan kompiler untuk sampai pada kesetaraan dalam sintaksis titik:
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);
}
Yang jika Anda jalankan Anda dapat memverifikasi bahwa itu lagi menghasilkan:
N = 1, O = 6, K = 4
... tetapi apakah Anda pernah menulis kode seperti ini?
Saya bertaruh jawabannya adalah NONBHN (Tidak Hanya Tidak, Tapi Tidak!) - karena terlalu rumit. Tentu Anda dapat membuat beberapa nama pengidentifikasi yang lebih bermakna daripada "temp0" .. "temp3", tetapi intinya adalah mereka tidak menambahkan apa pun pada kode - mereka tidak membuat kode bekerja lebih baik, mereka tidak membuat kode lebih baik dibaca, mereka hanya jelek kode, dan jika Anda melakukannya dengan tangan, tidak diragukan lagi Anda akan mengacaukannya satu atau tiga waktu sebelum memperbaikinya. Juga, bermain "permainan nama" cukup sulit untuk pengidentifikasi yang bermakna, jadi saya menyambut baik istirahat dari permainan nama yang diberikan kompiler kepada saya dalam pemahaman kueri.
Sampel puzzle ini mungkin tidak cukup nyata bagi Anda untuk dianggap serius; Namun, skenario lain memang ada di mana pemahaman kueri bersinar:
- Kompleksitas
Join
dan GroupJoin
: pelingkupan variabel rentang dalam join
klausa pemahaman kueri mengubah kesalahan yang mungkin dikompilasi dalam sintaksis titik menjadi kesalahan waktu kompilasi dalam sintaksis pemahaman.
- Setiap kali kompiler akan memperkenalkan pengidentifikasi transparan dalam transformasi pemahaman, pemahaman menjadi bermanfaat. Ini termasuk penggunaan salah satu dari yang berikut: beberapa
from
klausa, join
& join..into
klausa dan let
klausa.
Saya tahu lebih dari satu toko teknik di kota asal saya yang telah melarang sintaksis pemahaman. Saya pikir ini sangat disayangkan karena sintaks pemahaman hanyalah alat dan yang berguna pada saat itu. Saya pikir itu seperti mengatakan, "Ada hal-hal yang dapat Anda lakukan dengan obeng yang tidak dapat Anda lakukan dengan pahat. Karena Anda dapat menggunakan obeng sebagai pahat, pahat dilarang untuk selanjutnya di bawah keputusan raja."