Mencerminkan nama parameter: penyalahgunaan ekspresi C # lambda atau kecemerlangan sintaksis?

428

Saya melihat komponen MvcContrib Grid dan saya terpesona, namun pada saat yang sama jijik, oleh trik sintaksis yang digunakan dalam sintaks Grid :

.Attributes(style => "width:100%")

Sintaks di atas menetapkan atribut gaya HTML yang dihasilkan width:100%. Sekarang jika Anda memperhatikan, 'gaya' tidak ditentukan. Itu disimpulkan dari nama parameter dalam ekspresi! Saya harus menggali ini dan menemukan di mana 'keajaiban' terjadi:

Hash(params Func<object, TValue>[] hash)
{
    foreach (var func in hash)
    {
        Add(func.Method.GetParameters()[0].Name, func(null));
    }
}

Jadi memang, kode menggunakan formal, waktu kompilasi, nama parameter untuk membuat kamus pasangan nama-nilai atribut. Sintaks yang dihasilkan memang sangat ekspresif, tetapi pada saat yang sama sangat berbahaya.

Penggunaan umum ekspresi lambda memungkinkan penggantian nama yang digunakan tanpa efek samping. Saya melihat contoh di buku yang mengatakan collection.ForEach(book => Fire.Burn(book))saya tahu saya bisa menulis dalam kode saya collection.ForEach(log => Fire.Burn(log))dan itu artinya sama . Tetapi dengan sintaks MvcContrib Grid di sini tiba-tiba, saya menemukan kode yang secara aktif mencari dan membuat keputusan berdasarkan nama yang saya pilih untuk variabel saya!

Jadi apakah ini praktik umum dengan komunitas C # 3.5 / 4.0 dan pecinta ekspresi lambda? Atau maverick jahat yang tidak perlu saya khawatirkan?

Remus Rusanu
sumber
34
Saya berpendapat bahwa ini terlihat jelas, selama Anda bersedia melihat maksud kode, daripada hanya menguraikan sintaks. Yang, jika Anda membaca kode yang baik, adalah apa yang seharusnya Anda lakukan. Sintaks hanyalah wahana untuk niat, dan saya berpendapat bahwa ini adalah kode pengungkapan maksud.
Jamie Penney
191
Saya hanya bertanya kepada Anders (dan anggota tim desain lainnya) apa pendapat mereka. Anggap saja hasilnya tidak akan dicetak di surat kabar yang ramah keluarga.
Eric Lippert
22
C # saat ini tidak memiliki sintaks yang bersih dan ringan untuk peta, terutama peta yang diteruskan ke fungsi. Berbagai bahasa dinamis (Ruby, Python, JavaScript, ColdFusion 9) memiliki sintaks yang bersih dan ringan untuk itu, untuk beberapa perluasan atau lainnya.
yfeldblum
28
Oh, saya pikir itu terlihat menyenangkan. Adapun sintaks untuk peta, ya, akan lebih bagus jika kita bisa melakukan {{"Do" baru, "rusa"}, {"Re", "golden sun"} ...} dan minta kompiler menyimpulkan pembangunan peta, sama seperti yang baru [] {1, 2,3} menyimpulkan pembangunan array int. Kami sedang mempertimbangkan hal-hal semacam ini.
Eric Lippert
17
Eric Lippert, saya sangat menghormati Anda, tetapi saya pikir Anda dan kelompok (termasuk Anders, yang saya hormati dengan hebatnya FREAKIN ') membanting ini terlalu keras. Seperti yang Anda akui, C # tidak memiliki sintaks yang ketat untuk peta, dan beberapa versi lainnya (seperti Ruby) memiliki yang hebat. Orang ini menemukan cara untuk mendapatkan sintaks yang diinginkannya. Saya akan memberi Anda ada cara serupa untuk mengekspresikannya yang hampir sama ekspresifnya dengan sintaksnya dengan lebih sedikit kerugian. Tetapi sintaksnya dan fakta bahwa ia bekerja sangat keras untuk mendapatkannya dengan jelas menunjukkan perlunya peningkatan bahasa. Kinerja masa lalu menunjukkan kalian akan menciptakan sesuatu yang hebat untuk itu.
Charlie Flowers

Jawaban:

147

Ini memiliki interop yang buruk. Sebagai contoh, perhatikan contoh C # - F # ini

C #:

public class Class1
{
    public static void Foo(Func<object, string> f)
    {
        Console.WriteLine(f.Method.GetParameters()[0].Name);
    }
}

F #:

Class1.Foo(fun yadda -> "hello")

Hasil:

"arg" dicetak (bukan "yadda").

Akibatnya, perancang perpustakaan harus menghindari 'penyalahgunaan' semacam ini, atau setidaknya memberikan kelebihan 'standar' (misalnya yang menggunakan nama string sebagai parameter tambahan) jika mereka ingin memiliki interop yang bagus di seluruh bahasa .Net.

Brian
sumber
11
Kamu tidak. Strategi ini tidak portabel. (Dalam kasus ini membantu, sebagai contoh sebaliknya, F # dapat memiliki kelebihan metode yang berbeda hanya pada tipe pengembalian (tipe inferensi dapat melakukan itu). Hal ini dapat diekspresikan dalam CLR. Tetapi F # melarangnya, terutama karena jika Anda melakukannya, API-API itu tidak akan dapat dihubungi dari C #.) Ketika datang ke interop, selalu ada trade-off di fitur 'edge' mengenai manfaat apa yang Anda dapatkan dibandingkan dengan interop apa yang Anda trade off.
Brian
32
Saya tidak suka non interoperabilitas sebagai alasan untuk tidak melakukan sesuatu. Jika interoperabilitas adalah persyaratan maka lakukanlah, jika tidak, lalu mengapa khawatir tentang hal itu? Ini YAGNI IMHO.
John Farrell
15
@ jfar: Dalam. NET CLR interoperabilitas lahan memiliki dimenssi yang sama sekali baru, karena rakitan yang dihasilkan dalam kompiler apa pun seharusnya dikonsumsi dari bahasa lain .
Remus Rusanu
25
Saya setuju bahwa Anda tidak harus patuh pada CLS, tetapi sepertinya ide yang bagus jika Anda menulis perpustakaan atau kontrol (dan cuplikan yang memulai ini dari kisi, ya?) Jika tidak, Anda hanya membatasi audiens / basis pelanggan Anda
JMarsch
4
Mungkin ada baiknya mengubah: Fungsi <objek, string> ke Ekspresi << Fungsi <objek, string >> Dan jika Anda membatasi sisi kanan ekspresi hanya menjadi konstanta, Anda dapat memiliki implementasi yang melakukan ini: public static IDictionary <string, string> Hash (params Expression <Func <object, string >> [] hash) {Kamus <string, string> values ​​= Kamus baru <string, string> (); foreach (var func in hash) {values ​​[func.Parameters [0] .Name] = (string) ((ConstantExpression) func.Body) .Value; } mengembalikan nilai; }
davidfowl
154

Saya menemukan bahwa aneh bukan karena namanya , tetapi karena lambda tidak perlu ; itu bisa menggunakan tipe anonim dan lebih fleksibel:

.Attributes(new { style = "width:100%", @class="foo", blip=123 });

Ini adalah pola yang digunakan di sebagian besar ASP.NET MVC (misalnya), dan memiliki kegunaan lain ( peringatan , perhatikan juga pemikiran Ayende jika namanya adalah nilai ajaib daripada spesifik penelepon)

Marc Gravell
sumber
4
Ini juga memiliki masalah interop; tidak semua bahasa mendukung pembuatan jenis anonim seperti itu saat itu juga.
Brian
5
Saya suka bagaimana tidak ada yang benar-benar menjawab pertanyaan, sebaliknya orang memberikan argumen "ini lebih baik". : p Apakah itu penyalahgunaan atau tidak?
Sam Saffron
7
Saya akan tertarik melihat reaksi Eric Lippert terhadap ini. Karena itu dalam kode KERANGKA KERJA . Dan itu sama mengerikannya.
Matt Hinze
26
Saya tidak berpikir masalahnya adalah keterbacaan setelah kode telah ditulis. Saya pikir masalah sebenarnya adalah kemampuan mempelajari kode. Apa yang akan Anda pikirkan ketika intellisense Anda mengatakan .Attributes (objek keberatan) ? Anda harus membaca dokumentasi (yang tidak ingin dilakukan siapa pun) karena Anda tidak akan tahu harus meneruskan apa ke metode ini. Saya tidak berpikir ini benar-benar lebih baik daripada contoh dalam pertanyaan.
NotDan
2
@Arnis - mengapa lebih fleksibel: itu tidak bergantung pada nama parameter tersirat, yang mungkin (jangan kutip saya) menyebabkan masalah dengan beberapa implementasi lambda (bahasa lain) - tetapi Anda juga dapat menggunakan objek biasa dengan properti yang ditentukan. Misalnya, Anda bisa memiliki HtmlAttributeskelas dengan atribut yang diharapkan (untuk intellisense), dan hanya mengabaikan mereka dengan nullnilai-nilai ...
Marc Gravell
137

Hanya ingin memberikan pendapat saya (saya adalah penulis komponen grid MvcContrib).

Ini jelas merupakan penyalahgunaan bahasa - tidak diragukan lagi. Namun, saya tidak akan benar-benar menganggapnya kontra intuitif - ketika Anda melihat panggilan ke Attributes(style => "width:100%", @class => "foo")
saya pikir itu cukup jelas apa yang terjadi (Ini tentu saja tidak lebih buruk daripada pendekatan tipe anonim). Dari perspektif intellisense, saya setuju itu cukup buram.

Bagi yang berminat, beberapa info latar belakang tentang penggunaannya di MvcContrib ...

Saya menambahkan ini ke grid sebagai preferensi pribadi - Saya tidak suka penggunaan tipe anonim sebagai kamus (memiliki parameter yang mengambil "objek" sama buramnya dengan yang mengambil params Func []) dan initializer koleksi Kamus adalah agak bertele-tele (saya juga bukan penggemar antarmuka verbose yang fasih, misalnya harus menyatukan beberapa panggilan ke suatu Atribut ("style", "display: none"). Attribute ("class", "foo") dll)

Jika C # memiliki sintaksis kurang verbose untuk kamus literal, maka saya tidak akan repot memasukkan sintaks ini dalam komponen grid :)

Saya juga ingin menunjukkan bahwa penggunaan ini di MvcContrib sepenuhnya opsional - ini adalah metode ekstensi yang membungkus kelebihan yang mengambil IDictionary sebagai gantinya. Saya pikir sangat penting bahwa jika Anda memberikan metode seperti ini, Anda juga harus mendukung pendekatan yang lebih 'normal', misalnya untuk interop dengan bahasa lain.

Juga, seseorang menyebutkan 'overhead refleksi' dan saya hanya ingin menunjukkan bahwa sebenarnya tidak ada banyak overhead dengan pendekatan ini - tidak ada refleksi runtime atau kompilasi ekspresi yang terlibat (lihat http://blog.bittercoder.com /PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx ).

Jeremy Skinner
sumber
1
Saya juga mencoba untuk mengatasi beberapa masalah yang diangkat di sini secara lebih mendalam di blog saya: jeremyskinner.co.uk/2009/12/02/lambda-abuse-the-mvccontrib-hash
Jeremy Skinner
4
Tidak kurang buram di Intellisense dibandingkan objek anonim.
Brad Wilson
22
+1 untuk menyebutkan bahwa antarmuka ditambahkan melalui metode ekstensi opsional . Pengguna non C # (dan siapa pun yang tersinggung oleh penyalahgunaan bahasa) dapat dengan mudah menahannya.
Jørn Schou-Rode
50

saya akan lebih memilih

Attributes.Add(string name, string value);

Ini jauh lebih eksplisit dan standar dan tidak ada yang diperoleh dengan menggunakan lambdas.

NotDan
sumber
20
Apakah itu? html.Attributes.Add("style", "width:100%");tidak membaca sebaik style = "width:100%"(html aktual yang dihasilkan), sedangkan style => "width:100%"sangat dekat dengan apa yang tampak seperti dalam HTML yang dihasilkan.
Jamie Penney
6
Sintaks mereka memungkinkan untuk trik seperti .Attributes (id => 'foo', @class => 'bar', style => 'width: 100%'). Tanda tangan fungsi menggunakan sintaks params untuk jumlah variabel args: Attributes (params Func <object, object> [] args). Ini sangat kuat, tetapi butuh beberapa saat bagi saya untuk mengerti jika memang demikian.
Remus Rusanu
27
@ Jamie: Mencoba untuk membuat kode C # terlihat seperti kode HTML akan menjadi alasan buruk untuk keputusan desain. Mereka adalah bahasa yang sama sekali berbeda untuk tujuan yang sama sekali berbeda, dan mereka tidak boleh terlihat sama.
Guffa
17
Objek anonim mungkin saja telah digunakan, tanpa mengorbankan "keindahan"? .Attributes (new {id = "foo", @class = "bar", style = "width: 100%"}) ??
Funka
10
@ Guffa Mengapa itu menjadi alasan buruk untuk keputusan desain? Mengapa mereka tidak terlihat sama? Dengan alasan itu haruskah mereka sengaja terlihat berbeda? Saya tidak mengatakan kesalahan Anda, saya hanya mengatakan Anda mungkin ingin menjelaskan poin Anda lebih lengkap.
Samantha Branham
45

Selamat Datang di Rails Land :)

Tidak ada yang salah dengan itu selama Anda tahu apa yang terjadi. (Justru ketika hal semacam ini tidak didokumentasikan dengan baik bahwa ada masalah).

Keseluruhan kerangka Rails dibangun di atas gagasan konvensi atas konfigurasi. Memberi penamaan dengan cara-cara tertentu membuat Anda tertarik pada konvensi yang mereka gunakan dan Anda mendapatkan banyak fungsi secara gratis. Mengikuti konvensi penamaan akan membuat Anda lebih cepat. Semuanya bekerja dengan baik.

Tempat lain di mana saya pernah melihat trik seperti ini adalah dalam pemanggilan metode panggilan dalam Moq. Anda lulus lambda, tetapi lambda tidak pernah dieksekusi. Mereka hanya menggunakan ekspresi untuk memastikan bahwa pemanggilan metode terjadi dan melemparkan pengecualian jika tidak.

Jason Punyon
sumber
3
Saya agak ragu untuk melakukannya, tetapi saya setuju. Selain dari overhead refleksi, tidak ada perbedaan yang signifikan antara menggunakan string seperti pada Tambah () vs menggunakan nama parameter lambda. Setidaknya itu yang bisa saya pikirkan. Anda dapat membuangnya dan mengetik "sytle" tanpa memperhatikan kedua cara.
Samantha Branham
5
Saya tidak tahu mengapa ini tidak aneh bagi saya, dan kemudian saya ingat Rails. : D
Allyn
43

Ini mengerikan pada lebih dari satu level. Dan tidak, ini tidak seperti Ruby. Ini penyalahgunaan C # dan .NET.

Ada banyak saran tentang bagaimana melakukan ini dengan cara yang lebih mudah: tuple, tipe anonim, antarmuka yang lancar dan sebagainya.

Apa yang membuatnya begitu buruk adalah bahwa itu hanya cara untuk menghargai demi kebaikannya sendiri:

  • Apa yang terjadi ketika Anda perlu memanggil ini dari Visual Basic?

    .Attributes(Function(style) "width:100%")

  • Ini benar-benar berlawanan dengan intuisi, dan intellisense akan memberikan sedikit bantuan untuk mengetahui cara mengirimkan barang.

  • Itu tidak perlu tidak efisien.

  • Tidak ada yang akan tahu bagaimana cara mempertahankannya.

  • Apa jenis argumen yang masuk ke atribut? itu Func<object,string>? Bagaimana niat itu diungkapkan? Apa dokumentasi intellisense Anda akan berkata, "Harap abaikan semua nilai objek"?

Saya pikir Anda sepenuhnya dibenarkan memiliki perasaan jijik.

Sam Saffron
sumber
4
Saya akan mengatakan - itu sepenuhnya intuitif. :)
Arnis Lapsa
4
Anda mengatakan itu tidak seperti Ruby. Tapi itu adalah hal yang mengerikan seperti sintaks Ruby untuk menentukan kunci dan nilai hashtable.
Charlie Flowers
3
Kode yang rusak di bawah konversi alpha! Ya!
Phil
3
@Charlie, secara sintaksis terlihat sama, secara semantik berbeda.
Sam Saffron
39

Saya di kamp "sintaks kecemerlangan", jika mereka mendokumentasikannya dengan jelas, dan ini terlihat keren, hampir tidak ada masalah dengan imo!

Buta
sumber
10
Amin, saudara. Amin (amin ke-2 harus memenuhi panjang minimum untuk komentar :)
Charlie Flowers
Komentar Anda sendiri jauh lebih dari yang dibutuhkan. Tapi kemudian, Anda tidak bisa hanya Amin sekali dan kemudian memasukkan komentar Anda: D
Sleeper Smith
37

Keduanya. Ini penyalahgunaan ekspresi lambda DAN kecemerlangan sintaksis.

Arnis Lapsa
sumber
16
Jadi ini merupakan penyalahgunaan sintaksis ekspresi lambda yang brilian? Saya pikir saya setuju :)
Seth Petry-Johnson
21

Saya hampir tidak pernah menemukan penggunaan semacam ini. Saya pikir itu "tidak pantas" :)

Ini bukan cara penggunaan yang umum, ini tidak sesuai dengan konvensi umum. Sintaks semacam ini tentu saja memiliki pro dan kontra:

Cons

  • Kode tidak intuitif (konvensi biasa berbeda)
  • Itu cenderung rapuh (mengubah nama parameter akan merusak fungsionalitas).
  • Ini sedikit lebih sulit untuk diuji (memalsukan API akan membutuhkan penggunaan refleksi dalam pengujian).
  • Jika ekspresi digunakan secara intensif akan lebih lambat karena kebutuhan untuk menganalisis parameter dan bukan hanya nilai (biaya refleksi)

Pro

  • Ini lebih mudah dibaca setelah pengembang menyesuaikan diri dengan sintaks ini.

Intinya - dalam desain API publik saya akan memilih cara yang lebih eksplisit.

Elisa
sumber
2
@Elisha - Pro dan Kontra Anda dibalik. Setidaknya saya harap Anda tidak mengatakan bahwa Pro memiliki kode "tidak intuitif". ;-)
Metro Smurf
Untuk kasus khusus ini - nama parameter lambda dan parameter string keduanya rapuh. Ini seperti menggunakan dinamis untuk parsing xml - itu tepat karena Anda tidak dapat memastikan tentang xml.
Arnis Lapsa
19

Tidak, itu tentu bukan praktik yang umum. Ini kontra-intuitif, tidak ada cara hanya melihat kode untuk mengetahui apa fungsinya. Anda harus tahu bagaimana itu digunakan untuk memahami bagaimana itu digunakan.

Alih-alih memasok atribut menggunakan array delegasi, metode chaining akan lebih jelas dan berkinerja lebih baik:

.Attribute("style", "width:100%;").Attribute("class", "test")

Meskipun ini sedikit lebih banyak untuk diketik, ini jelas dan intuitif.

Guffa
sumber
6
Betulkah? Saya tahu persis apa maksud dari potongan kode itu ketika saya melihatnya. Itu tidak tumpul kecuali Anda sangat ketat. Kita bisa memberikan argumen yang sama tentang overloading + untuk string concatenation, dan kita harus selalu menggunakan metode Concat ().
Samantha Branham
4
@Stuart: Tidak, Anda tidak tahu persis, Anda hanya menebak berdasarkan nilai yang digunakan. Siapa pun dapat menebak, tetapi menebak bukanlah cara yang baik untuk memahami kode.
Guffa
11
Saya menebak menggunakan .Attribute("style", "width:100%")memberi saya style="width:100%", tetapi untuk semua yang saya tahu itu bisa memberi saya foooooo. Saya tidak melihat perbedaannya.
Samantha Branham
5
"Menebak berdasarkan nilai yang digunakan" adalah SELALU apa yang Anda lakukan ketika melihat kode. Jika Anda menemukan panggilan untuk streaming.tutup () Anda menganggap itu menutup aliran, namun mungkin juga melakukan sesuatu yang sama sekali berbeda.
Wouter Lievens
1
@Wouter: Jika Anda SELALU menebak-nebak ketika membaca kode, Anda pasti mengalami kesulitan besar membaca kode ... Jika saya melihat panggilan ke metode bernama "close" Saya dapat mengetahui bahwa pembuat kelas tidak tahu tentang konvensi penamaan , jadi saya akan sangat ragu untuk menerima apa saja tentang metode ini.
Guffa
17

Bisakah saya menggunakan ini untuk membuat frase?

magic lambda (n): fungsi lambda yang digunakan hanya untuk tujuan mengganti string sihir.

warga negara
sumber
ya ... itu lucu. dan mungkin itu agak ajaib, dalam arti tidak ada keamanan waktu kompilasi, adakah tempat di mana penggunaan ini akan menyebabkan runtime alih-alih kesalahan waktu kompilasi?
Maslow
17

Apa yang salah dengan yang berikut ini:

html.Attributes["style"] = "width:100%";
Tommy Carlier
sumber
16

Semua ini mengomel tentang "horridness" adalah sekelompok c # guys lama bereaksi berlebihan (dan saya seorang programmer C # lama dan masih penggemar bahasa). Tidak ada yang mengerikan tentang sintaks ini. Ini hanyalah upaya untuk membuat sintaksis terlihat lebih seperti apa yang Anda coba ekspresikan. Semakin sedikit "noise" yang ada dalam sintaks untuk sesuatu, semakin mudah programmer dapat memahaminya. Mengurangi kebisingan dalam satu baris kode hanya membantu sedikit, tetapi biarkan itu menumpuk di semakin banyak kode, dan ternyata menjadi manfaat besar.

Ini adalah upaya oleh penulis untuk mengupayakan manfaat yang sama dengan yang diberikan DSL kepada Anda - ketika kode hanya "terlihat seperti" apa yang Anda coba katakan, Anda telah mencapai tempat yang ajaib. Anda dapat memperdebatkan apakah ini baik untuk interop, atau apakah itu lebih baik daripada metode anonim untuk membenarkan beberapa biaya "kompleksitas". Cukup adil ... jadi dalam proyek Anda, Anda harus membuat pilihan yang tepat apakah akan menggunakan sintaksis semacam ini. Tapi tetap saja ... ini adalah upaya pintar oleh seorang programmer untuk melakukan apa, pada akhirnya, kita semua coba lakukan (apakah kita menyadarinya atau tidak). Dan apa yang kita semua coba lakukan, adalah ini: "Katakan pada komputer apa yang ingin kita lakukan dalam bahasa yang sedekat mungkin dengan cara kita berpikir tentang apa yang ingin dilakukan."

Semakin dekat dengan mengekspresikan instruksi kami ke komputer dengan cara yang sama yang kami pikir secara internal adalah kunci untuk membuat perangkat lunak lebih dapat dirawat dan lebih akurat.

EDIT: Saya telah mengatakan "kunci untuk membuat perangkat lunak lebih dapat dipelihara dan lebih akurat", yang merupakan sedikit unicorniness yang terlalu naif dan berlebihan. Saya mengubahnya menjadi "kunci."

Charlie Flowers
sumber
12

Ini adalah salah satu manfaat dari pohon ekspresi - seseorang dapat memeriksa kode itu sendiri untuk informasi tambahan. Itu adalah bagaimana .Where(e => e.Name == "Jamie")dapat dikonversi ke dalam klausa SQL Where yang setara. Ini adalah penggunaan cerdas pohon ekspresi, meskipun saya berharap itu tidak lebih jauh dari ini. Apa pun yang lebih kompleks kemungkinan akan lebih sulit daripada kode yang diharapkan untuk diganti, jadi saya menduga itu akan membatasi diri.

Jamie Penney
sumber
Adalah poin yang valid, tetapi kebenaran dalam periklanan: LINQ hadir dengan serangkaian atribut seperti TableAttribute dan ColumnAttribute yang menjadikan ini urusan yang lebih sah. Juga pemetaan linq melihat nama kelas dan nama properti, yang bisa dibilang lebih stabil daripada nama parameter.
Remus Rusanu
Saya setuju dengan Anda di sana. Saya telah mengubah sikap saya tentang ini sedikit setelah membaca apa yang dikatakan oleh Eric Lippert / Anders Helsberg / etc tentang masalah ini. Kupikir aku akan meninggalkan jawaban ini karena masih agak membantu. Untuk apa nilainya, saya sekarang berpikir gaya bekerja dengan HTML ini bagus, tetapi tidak sesuai dengan bahasa.
Jamie Penney
7

Ini merupakan pendekatan yang menarik. Jika Anda membatasi sisi kanan ekspresi menjadi konstanta hanya maka Anda bisa menerapkan menggunakan

Expression<Func<object, string>>

Yang saya pikir adalah apa yang sebenarnya Anda inginkan daripada delegasi (Anda menggunakan lambda untuk mendapatkan nama kedua belah pihak) Lihat implementasi naif di bawah ini:

public static IDictionary<string, string> Hash(params Expression<Func<object, string>>[] hash) {
    Dictionary<string, string> values = new Dictionary<string,string>();
    foreach (var func in hash) {
        values[func.Parameters[0].Name] = ((ConstantExpression)func.Body).Value.ToString();
    }
    return values;
}

Ini bahkan mungkin membahas masalah interop lintas bahasa yang disebutkan sebelumnya di utas.

dfowler
sumber
6

Kode ini sangat pintar, tetapi berpotensi menyebabkan lebih banyak masalah yang dipecahkan.

Seperti yang telah Anda tunjukkan, sekarang ada ketergantungan yang tidak jelas antara nama parameter (gaya) dan atribut HTML. Tidak ada pemeriksaan waktu kompilasi yang dilakukan. Jika nama parameter salah ketik, halaman mungkin tidak akan memiliki pesan kesalahan runtime, tetapi jauh lebih sulit untuk menemukan bug logika (tidak ada kesalahan, tetapi perilaku salah).

Solusi yang lebih baik adalah memiliki anggota data yang dapat diperiksa pada waktu kompilasi. Jadi alih-alih ini:

.Attributes(style => "width:100%");

kode dengan properti Style dapat diperiksa oleh kompiler:

.Attributes.Style = "width:100%";

atau bahkan:

.Attributes.Style.Width.Percent = 100;

Itu lebih banyak bekerja untuk pembuat kode, tetapi pendekatan ini mengambil keuntungan dari kemampuan pengecekan tipe C yang kuat, yang membantu mencegah bug masuk ke kode sejak awal.

Chris R. Timmons
sumber
3
Saya menghargai pemeriksaan waktu kompilasi, tapi saya pikir ini tergantung pada pendapat. Mungkin sesuatu seperti Atribut baru () {Style: "width: 100%"} akan memenangkan lebih banyak orang, karena ini lebih singkat. Tetap saja, menerapkan segala hal yang memungkinkan HTML adalah pekerjaan besar dan saya tidak dapat menyalahkan seseorang karena hanya menggunakan kelas string / lambdas / anonim.
Samantha Branham
5

memang sepertinya Ruby =), setidaknya bagi saya penggunaan sumber daya statis untuk "pencarian" dinamis nanti tidak cocok untuk pertimbangan desain api, harap trik pintar ini opsional di api itu.

Kami dapat mewarisi dari IDictionary (atau tidak) dan menyediakan pengindeks yang berperilaku seperti array php ketika Anda tidak perlu menambahkan kunci untuk menetapkan nilai. Ini akan menjadi penggunaan semantik Net yang valid bukan hanya c #, dan masih membutuhkan dokumentasi.

semoga ini membantu

Horacio N. Hdez.
sumber
4

Menurut pendapat saya itu adalah penyalahgunaan lambda.

Untuk sintaks kecemerlangan saya menemukan hal yang style=>"width:100%"membingungkan. Terutama karena =>bukan=

mfeingold
sumber
4

IMHO, ini adalah cara yang keren untuk melakukannya. Kita semua menyukai kenyataan bahwa penamaan Pengontrol kelas akan membuatnya menjadi pengontrol di MVC bukan? Jadi ada kasus di mana penamaan itu penting.

Niatnya juga sangat jelas di sini. Sangat mudah dipahami yang .Attribute( book => "something")akan menghasilkan book="something"dan .Attribute( log => "something")akan menghasilkanlog="something"

Saya kira itu seharusnya tidak menjadi masalah jika Anda memperlakukannya seperti sebuah konvensi. Saya berpendapat bahwa apa pun yang membuat Anda menulis lebih sedikit kode dan membuat niat menjadi jelas adalah hal yang baik.

madaboutcode
sumber
4
Memberi nama Pengontrol kelas tidak akan melakukan jongkok meskipun jika Anda tidak mewarisi dari pengontrol juga ...
Jordan Wallwork
3

Jika nama metode (func) dipilih dengan baik, maka ini adalah cara yang brilian untuk menghindari sakit kepala pemeliharaan (yaitu: menambahkan fungsi baru, tetapi lupa menambahkannya ke daftar pemetaan fungsi-parameter). Tentu saja, Anda perlu mendokumentasikannya dengan berat dan sebaiknya Anda membuat dokumentasi untuk parameter dari dokumentasi untuk fungsi di kelas tersebut secara otomatis ...

Craig Trader
sumber
1

Saya pikir ini tidak lebih baik daripada "string ajaib". Saya juga bukan penggemar jenis anonim untuk ini. Perlu pendekatan yang lebih baik & sangat diketik.

JamesK
sumber