Kapan saya harus menggunakan kelas 2-properti di atas struktur yang dibuat sebelumnya seperti KeyValuePair?

31

Kapan Anda harus memasukkan tipe data Key / Value di kelasnya sendiri alih-alih menggunakan struktur generik pra-bangun, seperti a KeyValuePairatau a Tuple?

Misalnya, sebagian besar Kotak Kombo yang saya buat mengandung DisplayName dan Nilai. Ini adalah jenis data yang saya coba putuskan kapan akan dimasukkan ke kelas baru, dan kapan harus menggunakan KeyValuePair.

Saat ini saya sedang mengerjakan sesuatu yang menggunakan iCalendar, dan data pengguna yang dipilih akhirnya digabungkan menjadi key1=value1;key2=value2;sejenis string. Saya mulai dengan memasukkan data ke dalam KeyValuePair<string,string>, tetapi sekarang saya bertanya-tanya apakah itu seharusnya kelas itu sendiri.

Secara keseluruhan, saya tertarik untuk mencari tahu pedoman apa yang digunakan ketika memutuskan untuk menggunakan struktur / kelas yang sudah ada seperti objek KeyValuePairlebih dari 2 properti, dan dalam situasi apa Anda akan menggunakan satu sama lain.

Rachel
sumber
3
Bahasa apa? Dalam Python, kami tidak memiliki dilema ini, karena kami memiliki tupletipe.
S.Lott
3
@ S.Lott - .NET BCL memiliki tupel sejak v 4.0.
Oded
1
.NET 4 juga memiliki tipe tuple. msdn.microsoft.com/en-us/library/system.tuple.aspx
Dave Nay
1
@Oded Dalam hal ini, saya sedang membangun sesuatu dengan iCalendardan saya ingin benda untuk BYDAYdan BYSETPOS. Mereka muncul di ComboBoxes, tetapi data aktual digabungkan ke dalam string aturan berulang, yang merupakan key=value;jenis string
Rachel
4
@Rachel: Harap perbarui pertanyaan untuk lebih spesifik. Banyak komentar bukan cara terbaik untuk mengklarifikasi hal-hal.
S.Lott

Jawaban:

26

Saya biasanya menggunakan objek daripada KeyValuePair atau Tuple dalam banyak kasus. Pertama, ketika Anda datang dalam 6 bulan kemudian untuk melakukan perubahan, jauh lebih mudah untuk mengetahui apa maksud Anda lebih awal daripada bertanya-tanya apa Tuple titu dan mengapa ia memiliki nilai-nilai lucu itu. Kedua, seiring pertumbuhan dan perubahan, Anda dapat dengan mudah memberikan perilaku objek transfer data sederhana sesuai kebutuhan. Perlu memiliki dua format nama? Mudah, tambahkan saja kelebihan ToString (). Perlu untuk mengimplementasikan beberapa antarmuka? Tidak masalah. Akhirnya, hampir tidak ada overhead untuk membuat objek sederhana, terutama dengan properti otomatis dan penyelesaian kode.

Bonus Protip: jika Anda ingin menjaga benda-benda ini dari mencemari namespace Anda, membuat kelas privat di dalam kelas adalah cara yang bagus untuk menjaga hal-hal tetap tersembunyi dan mencegah ketergantungan aneh.

Wyatt Barnett
sumber
1
DTOs = Objek Transfer Data ? - Saya benci TLA ;-)
Ben
3
@ Ben - TFTFY. . .
Wyatt Barnett
7

Aturan untuk mendefinisikan kelas baru adalah sederhana: Ini dirangkum oleh "Occam's Razor".

http://c2.com/cgi/wiki?OccamsRazor

Jangan memperkenalkan kelas baru tanpa alasan yang bagus. Atau gunakan kelas pra-bangun sebanyak mungkin. Atau ciptakan sesedikit mungkin. Namun Anda merasa nyaman menulis lebih sedikit kode.

Anda tidak dapat menggunakan kelas pra-dibangun jika Anda harus menetapkan beberapa tanggung jawab unik untuk objek dan tanggung jawab itu tidak didefinisikan dalam kelas pra-dibangun. Seringkali ini adalah metode yang unik.

A tupleatau KeyValuePairlebih disukai.

Sampai.

Anda memerlukan beberapa fungsionalitas yang bukan bagian dari A tupleatau KeyValuePair. Maka Anda harus mendefinisikan kelas Anda sendiri.

S.Lott
sumber
3
" Jangan pernah mendesain apa yang bisa kamu curi " Ini tentang cara favoritku untuk mengungkapkan ini.
SingleNegationElimination
1
Apakah Anda menganggap semantik sebagai "fungsionalitas yang bukan bagian dari a tupleatau KeyValuePair"? KeyValuePair setidaknya memiliki beberapa bentuk semantik, tetapi tuple jarang melakukannya (mungkin, tergantung pada konteks) imho. Memperkenalkan kelas baru seharusnya memberi Anda semantik yang jelas sebagai hal yang biasa.
Mal Ross
+1 Jangan menambal keseluruhan dalam perahu dengan lakban jika itu bisa pas colokan.
Evan Plaice
4
Saya pikir ini adalah penggunaan pisau cukur Occam yang salah tempat. Kedua, penting untuk mengetahui informasi apa yang terkandung dalam suatu variabel. -1.
Bent
4

Jika Anda menulis kelas Anda sendiri, Anda memiliki tempat yang jelas untuk meletakkan dokumentasi tentang apa kedua nilai tersebut. Terutama karena dua string bukanlah definisi yang sangat jelas. Namun Anda dapat menulis sesuatu seperti

 public class MyPair : Tuple<string, string>
Tanda
sumber
Saya suka ini karena MyPairmendefinisikan apa nilai Tuple dan untuk apa mereka digunakan.
IAbstract
2
Tetapi kemudian properti Anda akan dipanggil Item1dan Item2! Bukankah semudah mendefinisikan seluruh kelas? public class SideStrings { public string Left { get; set; } public string Right { get; set; } }
konfigurator
@configurator Saya menulis tanggapan untuk itu dan memperhatikan bahwa Tuple hanya dibaca jadi saya setuju yang menurut saya bisa memperdebatkan semuanya. Meskipun Anda bisa membungkus tuple untuk memberi nama nilai apa pun yang Anda inginkan.
Masuk
2
@ Sign: Tapi apa gunanya? Menciptakan kelas Anda sendiri adalah pekerjaan yang kurang dari membungkus tuple.
konfigurator
2
@configurator Anda mendapatkan beberapa persamaan dan perbandingan yang berfungsi lebih baik daripada objek kustom, tetapi jika pengaturan diperlukan, tuple jelas merupakan cara yang salah.
Masuk
4

S.Lott menulis

Jangan memperkenalkan kelas baru tanpa alasan yang bagus. Atau gunakan kelas pra-bangun sebanyak mungkin. Ciptakan sesedikit mungkin.

Anda tidak dapat menggunakan kelas pra-dibangun jika Anda harus menetapkan beberapa tanggung jawab unik untuk objek yang tidak didefinisikan dalam kelas pra-dibangun.

Biarkan saya mengatakan mengapa saya memiliki masalah serius dengan ini. Sejak

KeyValuePair [string, string]

tampaknya baik-baik saja .... apakah KeyValue [string, KeyValue [string, KeyValuePair [string, string]]] juga oke? Aku tidak tahu apa S. Lott akan mengatakan ini, tapi bos saya berpikir itu adalah apa apa.

Saya berani tidak setuju. Dan inilah alasannya: Ini mengurangi keterbacaan kode yang akan mengikuti. Fungsi yang akan mengisi struktur data seperti itu akan jauh lebih kompleks dan kesalahan (err .. pengecualian) cenderung (bayangkan setidaknya beberapa logika bisnis juga). Saya tidak berdebat dengan bos saya terlalu banyak, tapi aku akan mengatakan di sini: Keterbacaan mengalahkan penghematan ruang menit (yang nya argumen). Jadi tidak akan objek kelas di mana ada beberapa bidang; tetapi beberapa tetap kosong pada beberapa waktu menjadi lebih baik?

PS Saya seorang Ultra_Noob jadi tolong beri tahu saya jika saya salah.

Chani
sumber
2
Saya pikir itu KeyValuePair<string,string>baik-baik saja, dengan asumsi hal-hal yang dimasukkan memang kunci dan nilai. Di sini, menggunakan kembali kelas yang ada adalah kemenangan, karena Anda menyimpan kode penulisan dan mendapatkan interoperabilitas. OTOH, menggunakan sesuatu yang rumit seperti KeyValuePair<string,KeyValuePair<string,string>>kebanyakan waktu terlalu rumit untuk praktis. Kadang-kadang mungkin benar - ketika Anda tidak memerlukan fungsionalitas tambahan, ketika artinya jelas, dan ketika itu berfungsi dengan baik dengan kelas lain. YMMV, ini hanya menimbang pro dan kontra.
maaartinus
Jika Anda menggunakan C #, inilah kinerja Tuple vs KeyValuePair . Sesuatu yang mungkin ingin Anda bagikan dengan bos Anda?
Ben
3

Ketika kita mengatakan pasangan kunci / nilai , saya biasanya memikirkan tabel hash , atau array asosiatif , atau hanya KeyValuePair objek . Saya menggunakan semuanya dan tidak ada perbedaan kapan saya menggunakannya.

Saya pikir yang paling penting tentang daftar pasangan kunci / nilai adalah, kunci harus unik (karena ini memang kunci), dan semua struktur yang disebutkan di atas benar-benar memberi saya fungsionalitas itu.

Selain itu, saya ingin mencari berdasarkan tombol, atau melakukan tindakan gaya daftar (larik) seperti push dan pop.

Jadi, jawaban saya adalah, TIDAK , dan saya tidak membuat objek secara eksplisit untuk pasangan kunci / nilai, karena banyak struktur bawaan sudah melakukan itu untuk saya.

Saeed Neamati
sumber
3

Bab enam dari Kode Bersih memiliki deskripsi yang baik tentang kapan harus menggunakan struktur data versus kelas. Singkatnya, Anda menggunakan struktur data ketika Anda sebagian besar mengantisipasi menambahkan fungsi baru untuk beroperasi pada data itu. Anda menggunakan kelas saat Anda sebagian besar mengantisipasi menambahkan tipe data baru untuk dioperasikan oleh fungsi yang ada. ComboBox Anda adalah contoh dari yang terakhir. Anda memiliki satu set fungsi (implementasi ComboBox) yang beroperasi pada banyak tipe data yang berbeda (berbagai jenis data untuk widget yang berbeda).

Karl Bielefeldt
sumber
2

Saya mungkin akan setuju dengan Wilding di sini , tapi kemudian saya sedikit noob di hal semacam ini juga.

Saya akan menyarankan bahwa tipe built-in sering merupakan objek mekanisme . KeyValuePair misalnya, adalah bagian dari mekanisme kamus dan tabel hash, membantu memastikan kunci unik dan mereka memiliki properti yang memiliki nama yang bermakna dalam konteks mekanisme itu sendiri.

Di sisi lain, menggunakan objek data yang dibuat khusus memberikan representasi yang lebih baik dari data Anda dan memberikan banyak manfaat, termasuk keterbacaan dan ekstensibilitas. Tidak ada yang berhenti menggunakan kembali kode yang ada di objek yang dibuat khusus seperti yang disarankan Masuk , tapi saya akan mencoba dan menyembunyikan kelas yang dibungkus, dan menghindari kebocoran abstraksi , sehingga Anda dapat mengubah implementasi yang mendasarinya di titik kemudian tanpa mempengaruhi sisa kode Anda .

Jadi pertanyaan sebenarnya: Apakah Anda mewakili data atau Anda menggunakan data dalam suatu mekanisme? (dan saya tidak akan menyarankan menggabungkan konsep-konsep ini bersama-sama).

Dalam pengalaman saya, tidak ada yang lebih buruk dari melihat [string, string] Tuple dilewatkan ke dalam metode dan tidak memiliki cara langsung untuk mengetahui apa yang seharusnya menjadi Item1 dan Item2. Terbaik untuk menggunakan Tuples dalam metode atau sebagai anggota pribadi kelas saja.

Ben
sumber