Persyaratan apa yang dirancang untuk diselesaikan oleh tupel?


94

Saya melihat fitur C # baru dari tupel. Saya penasaran, masalah apa yang dirancang untuk diselesaikan oleh tupel?

Untuk apa Anda menggunakan tupel di aplikasi Anda?

Memperbarui

Terima kasih atas jawabannya sejauh ini, izinkan saya melihat apakah ada hal-hal yang terlintas dalam pikiran saya. Contoh yang baik dari tupel telah ditunjukkan sebagai koordinat. Apakah ini terlihat benar?

var coords = Tuple.Create(geoLat,geoLong);

Kemudian gunakan tupel seperti ini:

var myLatlng = new google.maps.LatLng("+ coords.Item1 + ", "+ coords.Item2 + ");

Apakah itu benar?



4
Baiklah, saya dapat memikirkan dua jawaban ...
Noon Silk

13
Jika konsep "koordinat" masuk akal sebagai kelas maka saya akan menjadikannya sebagai kelas. Gunakan tupel untuk situasi-situasi di mana ada tidak beberapa yang masuk akal "logika bisnis" konsep untuk set data yang membenarkan membuat tipe.
Eric Lippert

13
Koordinat bukanlah contoh tupel yang baik. Tuple di C # hanyalah solusi ad-hoc jika Anda harus mengembalikan (dari fungsi) dua nilai. Alih-alih menetapkan satu jenis hasil ditambah satu parameter keluar, lebih elegan untuk mengembalikan satu tupel. Dengan cara ini Anda tidak perlu mendeklarasikan parameter kedua terlebih dahulu. Perbedaannya bahkan lebih jelas dalam C ++ (Anda dapat mengubah hasilnya, tetapi Anda tidak dapat mengubah parameter out / ref).
greenoldman

8
Karena python memilikinya, dan python tidak dapat memiliki apa pun yang tidak dimiliki C #;)
Evan Plaice

Jawaban:


117

Saat menulis program, sangat umum untuk ingin secara logis mengelompokkan satu set nilai yang tidak memiliki kesamaan yang cukup untuk membenarkan pembuatan kelas.

Banyak bahasa pemrograman memungkinkan Anda untuk secara logis mengelompokkan sekumpulan nilai yang tidak terkait tanpa membuat tipe hanya dengan satu cara:

void M(int foo, string bar, double blah)

Logikanya ini persis sama dengan metode M yang mengambil satu argumen yang merupakan 3-tupel dari int, string, double. Tapi saya harap Anda tidak benar-benar membuat:

class MArguments
{
   public int Foo { get; private set; } 
   ... etc

kecuali MArguments memiliki arti lain dalam logika bisnis.

Konsep "mengelompokkan sekelompok data yang tidak terkait dalam beberapa struktur yang lebih ringan daripada kelas" berguna di banyak tempat, tidak hanya untuk daftar parameter formal metode. Ini berguna ketika sebuah metode memiliki dua hal untuk dikembalikan, atau ketika Anda ingin memasukkan kamus dari dua data, bukan satu, dan seterusnya.

Bahasa seperti F # yang mendukung jenis tuple secara native memberikan banyak fleksibilitas kepada penggunanya; mereka adalah kumpulan tipe data yang sangat berguna. Tim BCL memutuskan untuk bekerja dengan tim F # untuk membuat standarisasi pada satu jenis tupel untuk kerangka kerja sehingga setiap bahasa dapat memanfaatkannya.

Namun, saat ini belum ada dukungan bahasa untuk tupel di C #. Tuple hanyalah tipe data lain seperti kelas kerangka lainnya; tidak ada yang istimewa dari mereka. Kami sedang mempertimbangkan untuk menambahkan dukungan yang lebih baik untuk tupel dalam versi hipotetis C # yang akan datang. Jika ada yang memiliki pemikiran tentang fitur apa yang melibatkan tupel yang ingin Anda lihat, saya akan dengan senang hati menyampaikannya kepada tim desain. Skenario realistis lebih meyakinkan daripada renungan teoretis.


1
@MalcomTucker: Asikroni dan paralelisme pasti ada di benak kami sebagai area kaya tempat alat bahasa dapat digunakan untuk memecahkan masalah nyata. Saya tidak berpikir bahwa alur kerja asinkron gaya F # pasti paling cocok untuk C #, tetapi mereka pasti menginspirasi.
Eric Lippert

60
Meskipun tupel berguna, satu kelemahan besar adalah kejelasan. Sulit untuk membaca dan memahami kode yang merujuk ke Item1,, Item2dll ... Jika tuple pernah mencapai dukungan bahasa di C #, akan sangat bagus untuk mengizinkan anggotanya diberi nama (atau setidaknya alias) dengan cara yang memungkinkan kode yang menggunakan agar lebih bisa dimengerti. Dalam masa depan yang hipthetis, saya juga ingin melihat tupel dengan "bentuk" yang sesuai sebagai parameter hukum untuk metode yang mengambil parameter individu (dan sebaliknya). Jadi, Tuple<int,string,bool>bisa diteruskan ke M(int,string,bool). Ini akan membuat metode memo menjadi lebih mudah.
LBushkin

2
Ini "tuple" pada dasarnya semua publicakses, tipe anonim struct dengan anggota yang tidak disebutkan namanya . Saya lebih suka programmer menulis structdengan nama anggota dan mengembalikannya, daripada harus berurusan dengan tupleyang tidak memberi tahu saya apa pun tentang semantik anggotanya.
bobobobo

1
@ Hi-Angel: Argumennya bukan tentang berdalih tentang apa yang dianggap sebagai tupel dan apa yang tidak, melainkan tentang apa yang merupakan kumpulan fitur yang dapat digunakan oleh pengembang lini bisnis modern untuk meningkatkan produktivitas mereka . LBushkin mengungkapkan permintaan fitur yang selalu didengar oleh tim desain: keinginan untuk membuat "tipe rekaman" dari beberapa jenis tanpa kesulitan dan biaya untuk membuat seluruh kelas hanya untuk menampung beberapa bidang. C # sudah memiliki fitur ini untuk metode; itu disebut "daftar parameter".
Eric Lippert

2
@ Hi-Angel: Anda mungkin tidak akan membuat argumen "jika Anda ingin mengakses parameter metode Anda dengan nama maka Anda harus membuat kelas terpisah" karena itu tampak sangat berat, tetapi itu hanya tampak berat karena kita terbiasa memiliki kemampuan untuk langsung mengikat satu set variabel arbitrer dengan jenis dan nama arbitrer saat memanggil metode . Bayangkan tidak ada bahasa yang memiliki fitur itu; setiap metode hanya dapat mengambil satu argumen, dan jika Anda ingin meneruskan dua, Anda harus membuat sebuah tipe dan mengirimkan sebuah contoh darinya.
Eric Lippert

22

Tuple menyediakan implementasi koleksi yang tidak dapat diubah

Selain dari penggunaan umum tupel:

  • untuk mengelompokkan nilai-nilai bersama tanpa harus membuat kelas
  • untuk mengembalikan beberapa nilai dari fungsi / metode
  • dll ...

Objek yang tidak dapat diubah pada dasarnya aman untuk thread:

Objek yang tidak dapat diubah dapat berguna dalam aplikasi multi-utas. Beberapa utas dapat bertindak pada data yang diwakili oleh objek tetap tanpa khawatir data diubah oleh utas lain. Oleh karena itu, objek yang tidak dapat diubah dianggap lebih aman untuk thread daripada objek yang bisa berubah.

Dari "Objek Abadi" di wikipedia


Terima kasih telah menambahkan info tambahan ke pertanyaan itu. Sangat dihargai.
Chaddeus

Jika Anda menginginkan koleksi yang tidak dapat diubah, Anda harus menggunakan koleksi yang tidak dapat diubah, bukan Tuple. Perbedaannya adalah bahwa untuk sebagian besar koleksi yang tidak dapat diubah, Anda tidak perlu menentukan jumlah elemen pada waktu kompilasi
BlueRaja - Danny Pflughoeft

@ BlueRaja-DannyPflughoeft Kembali ketika saya menulis jawaban ini kelas koleksi C # yang tidak dapat diubah masih belum tersedia di BCL. Kira saya akan mengubah 'koleksi' menjadi 'objek' karena MS mensterilkan implementasi Tuple di C #
Evan Plaice

12

Ini memberikan alternatif untuk refatauout jika Anda memiliki metode yang perlu mengembalikan beberapa objek baru sebagai bagian dari responsnya.

Ini juga memungkinkan Anda untuk menggunakan tipe bawaan sebagai tipe kembalian jika yang perlu Anda lakukan hanyalah menggabungkan dua atau tiga tipe yang ada, dan Anda tidak ingin menambahkan kelas / struct hanya untuk kombinasi ini. (Pernah berharap suatu fungsi dapat mengembalikan tipe anonim? Ini adalah jawaban parsial untuk situasi itu.)


Sial. Bagus. Saya berharap saya telah memeriksa apa-tuple-are beberapa tahun yang lalu;).
sabiland



4

Secara pribadi, saya menemukan Tuple menjadi bagian berulang dari perkembangan ketika Anda berada dalam siklus investigasi, atau hanya "bermain". Karena Tuple bersifat generik, saya cenderung memikirkannya saat bekerja dengan parameter generik - terutama saat ingin mengembangkan bagian kode generik, dan saya mulai dari bagian akhir kode, daripada bertanya pada diri sendiri "bagaimana saya akan menyukai panggilan ini untuk melihat?".

Cukup sering saya menyadari bahwa koleksi yang dibentuk Tuple menjadi bagian dari sebuah daftar, dan menatap List> tidak benar-benar mengungkapkan maksud dari daftar tersebut, atau cara kerjanya. Saya sering "hidup" dengannya, tetapi mendapati diri saya ingin memanipulasi daftar, dan mengubah nilai - pada titik mana, saya tidak perlu membuat Tuple baru untuk itu, jadi saya perlu membuat kelas atau struct saya sendiri untuk menahannya, jadi saya bisa menambahkan kode manipulasi.

Tentu saja, selalu ada metode ekstensi - tetapi sering kali Anda tidak ingin memperluas kode tambahan itu ke implementasi umum.

Ada kalanya saya ingin mengekspresikan data sebagai Tuple, dan tidak memiliki Tupel yang tersedia. (VS2008) dalam hal ini saya baru saja membuat kelas Tuple saya sendiri - dan saya tidak membuatnya aman untuk thread (tidak dapat diubah).

Jadi saya kira saya berpendapat bahwa Tuple adalah pemograman malas dengan mengorbankan kehilangan nama jenis yang menjelaskan tujuannya. Biaya lainnya adalah Anda harus mendeklarasikan tanda tangan Tuple di mana pun itu digunakan sebagai parameter. Setelah sejumlah metode yang mulai terlihat membengkak, Anda mungkin merasa seperti saya, bahwa ada baiknya membuat kelas, karena membersihkan tanda tangan metode.

Saya cenderung memulai dengan menjadikan kelas sebagai anggota publik dari kelas yang sudah Anda kerjakan. Tetapi saat itu melampaui sekadar kumpulan nilai, ia mendapatkan file itu sendiri, dan saya memindahkannya dari kelas yang memuatnya.

Jadi dalam retrospeksi, saya percaya saya menggunakan Tuple ketika saya tidak ingin pergi dan menulis kelas, dan hanya ingin memikirkan tentang apa yang saya tulis sekarang. Yang berarti tanda tangan Tuple dapat berubah cukup banyak dalam teks setengah jam sementara saya mencari tahu data apa yang saya perlukan untuk metode ini, dan bagaimana ia mengembalikan nilai apa pun yang akan dikembalikannya.

Jika saya mendapat kesempatan untuk merefaktor kode, maka sering kali saya akan mempertanyakan tempat Tuple di dalamnya.


3

Pertanyaan lama sejak 2010, dan sekarang di 2017 Dotnet berubah dan menjadi lebih pintar.

C # 7 memperkenalkan dukungan bahasa untuk tupel, yang memungkinkan nama semantik untuk bidang tupel menggunakan jenis tupel baru yang lebih efisien.

Di vs 2017 dan .Net 4.7 (atau menginstal paket nuget System.ValueTuple), Anda dapat membuat / menggunakan tupel dengan cara yang sangat efisien dan sederhana:

     var person = (Id:"123", Name:"john"); //create tuble with two items
     Console.WriteLine($"{person.Id} name:{person.Name}") //access its fields

Mengembalikan lebih dari satu nilai dari sebuah metode:

    public (double sum, double average) ComputeSumAndAverage(List<double> list)
    {
       var sum= list.Sum();
        var average = sum/list.Count;
        return (sum, average);
    }

    How to use:

        var list=new List<double>{1,2,3};
        var result = ComputeSumAndAverage(list);
        Console.WriteLine($"Sum={result.sum} Average={result.average}");    

Untuk lebih jelasnya baca: https://docs.microsoft.com/en-us/dotnet/csharp/tuples


1

Tuple sering digunakan untuk mengembalikan beberapa nilai dari fungsi saat Anda tidak ingin membuat tipe tertentu. Jika Anda terbiasa dengan Python, Python sudah memiliki ini sejak lama.


1

Menampilkan lebih dari satu nilai dari sebuah fungsi. getCoordinates () tidak terlalu berguna jika hanya mengembalikan x atau y atau z, tetapi membuat kelas dan objek penuh untuk menampung tiga int juga tampaknya cukup kelas berat.


1

Penggunaan umum mungkin untuk menghindari pembuatan kelas / struct yang hanya berisi 2 bidang, sebagai gantinya Anda membuat Tuple (atau KeyValuePair untuk saat ini). Berguna sebagai nilai kembali, hindari melewatkan N keluar params ...


0

Saya menemukan KeyValuePair menyegarkan di C # untuk mengulangi pasangan nilai kunci dalam Kamus.


KeyValuePairdapat dipandang sebagai solusi tujuan khusus. Dalam Python, melakukan iterasi atas dicttupel just return (key, value).
dan04

Ya, seperti python. :-) Saya tidak tahu bahwa KeyValuePair di c # bukan tuple?
Jubal

0

Ini sangat membantu saat mengembalikan nilai dari fungsi. Kami dapat memiliki beberapa nilai kembali dan ini cukup hemat dalam beberapa skenario.


0

Saya menemukan tolok ukur kinerja antara pasangan Tuple dan Key-Value ini dan mungkin Anda akan menganggapnya menarik. Singkatnya dikatakan bahwa Tuple memiliki keuntungan karena ini adalah kelas, oleh karena itu disimpan di heap dan bukan di tumpukan dan ketika diedarkan sebagai argumen, penunjuknya adalah satu-satunya hal yang berjalan. Tapi KeyValuePair adalah struct sehingga lebih cepat untuk dialokasikan tetapi lebih lambat saat digunakan.

http://www.dotnetperls.com/tuple-keyvaluepair

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.