Dengan tambahan kelas Tuple di .net 4, saya telah mencoba memutuskan apakah menggunakannya dalam desain saya adalah pilihan yang buruk atau tidak. Cara saya melihatnya, Tuple bisa menjadi jalan pintas untuk menulis kelas hasil (saya yakin ada kegunaan lain juga).
Jadi ini:
public class ResultType
{
public string StringValue { get; set; }
public int IntValue { get; set; }
}
public ResultType GetAClassedValue()
{
//..Do Some Stuff
ResultType result = new ResultType { StringValue = "A String", IntValue = 2 };
return result;
}
Setara dengan ini:
public Tuple<string, int> GetATupledValue()
{
//...Do Some stuff
Tuple<string, int> result = new Tuple<string, int>("A String", 2);
return result;
}
Jadi mengesampingkan kemungkinan bahwa saya kehilangan titik Tuples, apakah contoh dengan Tuple pilihan desain yang buruk? Bagi saya sepertinya kurang berantakan, tetapi tidak mendokumentasikan dan membersihkan diri. Berarti dengan tipe tersebut ResultType
, sangat jelas nanti tentang apa arti setiap bagian dari kelas tetapi Anda memiliki kode tambahan untuk dipelihara. Dengan itu Tuple<string, int>
Anda harus mencari dan mencari tahu apa yang masing-masing Item
wakili, tetapi Anda menulis dan mempertahankan lebih sedikit kode.
Pengalaman apa pun yang Anda miliki dengan pilihan ini akan sangat dihargai.
sumber
Jawaban:
Tuples sangat bagus jika Anda mengontrol keduanya membuat dan menggunakannya - Anda dapat mempertahankan konteks, yang penting untuk memahaminya.
Namun, pada API publik, mereka kurang efektif. Konsumen (bukan Anda) harus menebak atau mencari dokumentasi, terutama untuk hal-hal seperti
Tuple<int, int>
.Saya akan menggunakannya untuk anggota pribadi / internal, tetapi menggunakan kelas hasil untuk anggota publik / yang dilindungi.
Jawaban ini juga memiliki beberapa info.
sumber
StringOps
(pada dasarnya kelas "metode ekstensi" untuk JavaString
) memiliki metodeparition(Char => Boolean): (String, String)
(mengambil predikat, mengembalikan tuple dari 2 string). Sudah jelas apa outputnya (jelas yang akan menjadi karakter yang predikatnya benar dan yang lain yang salah, tetapi tidak jelas yang mana). Dokumentasinya yang menjelaskan hal ini (dan pencocokan pola dapat digunakan untuk memperjelas dalam penggunaan yang mana).Memang ada kegunaan lain yang berharga untuk
Tuple<>
- sebagian besar dari mereka melibatkan abstrak semantik kelompok jenis tertentu yang berbagi struktur yang sama, dan memperlakukan mereka hanya sebagai seperangkat nilai yang dipesan. Dalam semua kasus, keuntungan dari tuple adalah mereka menghindari mengacaukan namespace Anda dengan kelas hanya data yang mengekspos properti tetapi bukan metode.Berikut adalah contoh penggunaan yang masuk akal untuk
Tuple<>
:Dalam contoh di atas kami ingin mewakili sepasang lawan, tuple adalah cara yang mudah untuk memasangkan instance ini tanpa harus membuat kelas baru. Ini contoh lain:
Tangan poker dapat dianggap sebagai hanya satu set kartu - dan tuple (mungkin) cara yang wajar untuk mengekspresikan konsep itu.
Mengembalikan
Tuple<>
instance yang sangat diketik sebagai bagian dari API publik untuk tipe publik jarang merupakan ide yang bagus. Seperti yang Anda ketahui sendiri, tuple mengharuskan pihak-pihak yang terlibat (penulis perpustakaan, pengguna perpustakaan) untuk menyetujui sebelumnya mengenai tujuan dan interpretasi jenis tuple yang digunakan. Cukup menantang untuk membuat API yang intuitif dan jelas, menggunakanTuple<>
secara publik hanya mengaburkan niat dan perilaku API.Jenis anonim juga merupakan jenis tuple - namun, mereka sangat diketik dan memungkinkan Anda menentukan nama yang jelas dan informatif untuk properti yang termasuk dalam jenis tersebut. Tetapi jenis anonim sulit digunakan di berbagai metode - mereka terutama ditambahkan untuk mendukung teknologi seperti LINQ di mana proyeksi akan menghasilkan jenis yang biasanya kita tidak ingin menetapkan nama. (Ya, saya tahu bahwa tipe anonim dengan tipe dan properti yang sama dikonsolidasikan oleh kompiler).
Aturan praktis saya adalah: jika Anda akan mengembalikannya dari antarmuka publik Anda - jadikan ini tipe yang dinamai .
Aturan praktis saya yang lain untuk menggunakan tuple adalah: argumen metode nama dan variabel tipe localc
Tuple<>
sejelas mungkin - membuat nama tersebut mewakili makna hubungan antara elemen tuple. Pikirkanvar opponents = ...
contoh saya .Berikut adalah contoh kasus dunia nyata di mana saya terbiasa
Tuple<>
menghindari menyatakan tipe data saja untuk digunakan hanya dalam perakitan saya sendiri . Situasi ini melibatkan fakta bahwa ketika menggunakan kamus umum yang berisi tipe anonim, menjadi sulit untuk menggunakanTryGetValue()
metode untuk menemukan item dalam kamus karena metode ini membutuhkanout
parameter yang tidak dapat disebutkan namanya:PS Ada cara lain (lebih sederhana) untuk mengatasi masalah yang muncul dari jenis anonim dalam kamus, dan itu adalah dengan menggunakan
var
kata kunci untuk membiarkan kompiler 'menyimpulkan' jenis untuk Anda. Inilah versi itu:sumber
Tuple<>
bisa masuk akal. Selalu ada alternatif ...Tuples bisa bermanfaat ... tetapi nantinya bisa menjadi sakit. Jika Anda memiliki metode yang mengembalikan
Tuple<int,string,string,int>
bagaimana Anda tahu apa nilai-nilai itu nantinya. Apakah merekaID, FirstName, LastName, Age
atau tidakUnitNumber, Street, City, ZipCode
.sumber
Tuples adalah tambahan yang cukup underwhelming untuk CLR dari perspektif programmer C #. Jika Anda memiliki koleksi item yang panjangnya bervariasi, Anda tidak perlu mereka memiliki nama statis yang unik pada waktu kompilasi.
Tetapi jika Anda memiliki koleksi panjang konstan, ini menyiratkan bahwa tetap lokasi dalam koleksi masing-masing memiliki makna yang telah ditentukan sebelumnya. Dan itu selalu lebih baik untuk memberi mereka nama-nama statis yang tepat dalam kasus itu, daripada harus mengingat pentingnya
Item1
,Item2
dllKelas anonim di C # sudah memberikan solusi luar biasa untuk penggunaan pribadi paling umum dari tupel, dan mereka memberikan nama yang bermakna untuk item tersebut, sehingga mereka sebenarnya lebih unggul dalam hal itu. Satu-satunya masalah adalah mereka tidak bisa keluar dari metode yang disebutkan. Saya lebih suka melihat bahwa pembatasan dicabut (mungkin hanya untuk metode pribadi) daripada memiliki dukungan khusus untuk tupel dalam C #:
sumber
struct var SimpleStruct {int x, int y;}
akan mendefinisikan sebuah struct dengan nama yang dimulai dengan panduan yang terkait dengan struct sederhana dan memiliki sesuatu seperti{System.Int16 x}{System.Int16 y}
ditambahkan; nama apa pun yang dimulai dengan GUID itu akan diminta untuk mewakili suatu struct yang hanya mengandung elemen-elemen dan konten tertentu yang ditentukan; jika beberapa definisi untuk nama yang sama berada dalam ruang lingkup dan mereka cocok, semua akan dianggap tipe yang sama.ref
parameter tunggal , satu-satunya cara adalah mungkin untuk memiliki satu delegasi yang dapat diteruskan ke kedua fungsi adalah jika satu orang menghasilkan dan mengkompilasi sebuah jenis delegasi dan memberikannya kepada yang lain untuk membangun melawan. Tidak mungkin kedua orang dapat menunjukkan bahwa kedua jenis ini harus dianggap sama.Tuple
? Saya baru saja menelusuri 50 tempat di basis kode saya di mana saya menggunakan tuple, dan semuanya adalah nilai pengembalian (biasanyayield return
) atau merupakan elemen koleksi yang digunakan di tempat lain, jadi jangan gunakan kelas anonim.Mirip dengan kata kunci
var
, ini dimaksudkan sebagai kenyamanan - tetapi juga mudah disalahgunakan.Menurut pendapat saya yang paling sederhana, jangan mengekspos
Tuple
sebagai kelas kembali. Gunakan secara pribadi, jika layanan atau struktur data komponen memerlukannya, tetapi kembalikan kelas-kelas terkenal yang terbentuk dari metode publik.sumber
var
tidak dapat dikembalikan atau ada di luar ruang lingkup yang dinyatakan. namun, masih memungkinkan untuk menggunakannya melebihi tujuan yang dimaksudkan dan "disalahgunakan"Menggunakan kelas seperti
ResultType
ini lebih jelas. Anda dapat memberikan nama yang bermakna ke bidang di kelas (sedangkan dengan tupel mereka akan dipanggilItem1
danItem2
). Ini bahkan lebih penting jika jenis kedua bidang itu sama: namanya jelas membedakan keduanya.sumber
Bagaimana kalau menggunakan Tuples dalam pola hiasi-semacam-tidak-dekorasi? (Transformasi Schwartzian untuk orang Perl). Inilah contoh yang dibuat-buat, untuk memastikan, tetapi Tuples tampaknya menjadi cara yang baik untuk menangani hal semacam ini:
Sekarang, saya bisa menggunakan Object [] dari dua elemen atau dalam contoh khusus ini string [] dari dua elemen. Intinya adalah bahwa saya bisa menggunakan apa pun sebagai elemen kedua dalam Tuple yang digunakan secara internal dan cukup mudah dibaca.
sumber
IMO "tuple" ini pada dasarnya semua
struct
jenis akses publik anonim dengan anggota yang tidak disebutkan namanya .Satu- satunya tempat saya akan menggunakan tuple adalah ketika Anda perlu dengan cepat mengumpulkan beberapa data, dalam cakupan yang sangat terbatas. Semantik data harus jelas , sehingga kodenya tidak sulit dibaca. Jadi menggunakan tuple (
int
,int
) untuk (baris, col) tampaknya masuk akal. Tapi saya sulit sekali menemukan keunggulan dibandingkanstruct
dengan anggota bernama (jadi tidak ada kesalahan dibuat dan baris / kolom tidak sengaja saling dipertukarkan)Jika Anda mengirim data kembali ke penelepon, atau menerima data dari penelepon, Anda harus benar-benar menggunakan anggota yang
struct
bernama.Ambil contoh sederhana:
Versi tuple
Saya tidak melihat keuntungan menggunakan tuple di tempat struct dengan anggota bernama. Menggunakan anggota yang tidak disebutkan namanya adalah langkah mundur untuk keterbacaan dan pemahaman kode Anda.
Tuple menganggap saya sebagai cara malas untuk menghindari membuat
struct
dengan anggota bernama sebenarnya. Terlalu sering menggunakan tuple, di mana Anda benar-benar merasa Anda / atau orang lain menemukan kode Anda akan membutuhkan anggota bernama A Bad Thing ™ jika saya pernah melihatnya.sumber
Jangan menilai saya, saya bukan ahli, tetapi dengan Tuples baru di C # 7.x sekarang, Anda dapat mengembalikan sesuatu seperti:
Setidaknya sekarang Anda dapat memberi nama dan pengembang mungkin melihat beberapa informasi.
sumber
Itu tergantung, tentu saja! Seperti yang Anda katakan, sebuah tuple dapat menghemat kode dan waktu Anda saat Anda ingin mengelompokkan beberapa item bersama untuk konsumsi lokal. Anda juga dapat menggunakannya untuk membuat lebih banyak algoritme pemrosesan generik daripada yang dapat Anda lakukan jika melewati kelas yang konkret. Saya tidak ingat berapa kali saya berharap memiliki sesuatu di luar KeyValuePair atau DataRow untuk dengan cepat melewatkan beberapa tanggal dari satu metode ke metode lainnya.
Di sisi lain, sangat mungkin untuk melakukannya secara berlebihan dan mengedarkan tuple di mana Anda hanya bisa menebak isinya. Jika Anda akan menggunakan tuple lintas kelas, mungkin akan lebih baik untuk membuat satu kelas konkret.
Tentu saja, digunakan dalam jumlah sedang, tupel dapat menghasilkan kode yang lebih ringkas dan mudah dibaca. Anda dapat melihat C ++, STL, dan Boost untuk contoh bagaimana Tuples digunakan dalam bahasa lain, tetapi pada akhirnya, kita semua harus bereksperimen untuk menemukan cara yang paling sesuai dengan lingkungan .NET.
sumber
Tuples adalah fitur framework yang tidak berguna di .NET 4. Saya pikir peluang besar terlewatkan dengan C # 4.0. Saya akan senang memiliki tuple dengan anggota bernama, sehingga Anda dapat mengakses berbagai bidang tuple dengan nama, bukan Value1 , Value2 , dll ...
Itu akan membutuhkan perubahan bahasa (sintaks), tetapi itu akan sangat berguna.
sumber
let success, value = MethodThatReturnsATuple()
Saya pribadi tidak akan pernah menggunakan Tuple sebagai tipe pengembalian karena tidak ada indikasi nilai yang diwakilinya. Tuples memiliki beberapa kegunaan yang berharga karena tidak seperti objek mereka adalah tipe nilai dan dengan demikian memahami kesetaraan. Karena ini saya akan menggunakannya sebagai kunci kamus jika saya memerlukan kunci multi bagian atau sebagai kunci untuk klausa GroupBy jika saya ingin mengelompokkan berdasarkan beberapa variabel dan tidak ingin pengelompokan bersarang (Siapa yang ingin pengelompokan bersarang?). Untuk mengatasi masalah dengan verbositas ekstrem, Anda dapat membuatnya dengan metode pembantu. Perlu diingat jika Anda sering mengakses anggota (melalui Item1, Item2, dll) maka Anda mungkin harus menggunakan konstruk yang berbeda seperti struct atau kelas anonim.
sumber
Saya telah menggunakan tupel, baik yang baru
Tuple
maupun yang baruValueTuple
, dalam sejumlah skenario yang berbeda dan sampai pada kesimpulan berikut: jangan gunakan .Setiap kali, saya mengalami masalah berikut:
Pendapat saya adalah tuple adalah kerugian, bukan fitur, dari C #.
Saya agak mirip, tetapi kurang kasar, kritik terhadap
Func<>
danAction<>
. Itu berguna dalam banyak situasi, terutama varian yang sederhanaAction
danFunc<type>
, tetapi lebih dari itu, saya menemukan bahwa membuat tipe delegasi lebih elegan, mudah dibaca, dapat dipelihara, dan memberi Anda lebih banyak fitur, sepertiref
/out
parameter.sumber
ValueTuple
- dan saya juga tidak menyukainya. Pertama, penamaannya tidak kuat, ini lebih merupakan saran, sangat mudah untuk dikacaukan karena dapat ditetapkan secara implisit ke salah satuTuple
atauValueTuple
dengan jumlah dan jenis item yang sama. Kedua, kurangnya pewarisan dan kebutuhan untuk menyalin seluruh definisi dari satu tempat ke tempat lain masih merugikan.