Demet hangi gereksinimi çözmek için tasarlanmıştı?


94

Demetlerin yeni C # özelliğine bakıyorum. Merak ediyorum, tuple hangi sorunu çözmek için tasarlandı?

Uygulamalarınızda tuple'ı ne için kullandınız?

Güncelleme

Şimdiye kadarki cevaplar için teşekkürler, aklımda bir şeyler olup olmadığını görmeme izin verin. Bir demet için güzel bir örnek koordinatlar olarak gösterildi. Bu doğru görünüyor mu?

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

Ardından demeti şu şekilde kullanın:

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

Bu doğru mu?



4
İki cevap düşünebilirim ...
Noon Silk

13
"Koordinat" kavramı sınıf olarak mantıklıysa, o zaman onu bir sınıf yapardım. Bir tür oluşturmayı haklı çıkaran veri kümesi için bazı mantıklı "iş mantığı" kavramının olmadığı durumlar için tuple kullanın .
Eric Lippert

13
Koordinatlar, demet için iyi bir örnek değildir. C # 'da Tuple, (bir işlevden) iki değer döndürmeniz gereken durumlarda yalnızca geçici bir çözümdür. Bir sonuç türü artı bir çıkış parametresi ayarlamak yerine, bir demet döndürmek daha zariftir. Bu şekilde, ikinci parametreyi önceden bildirmeniz gerekmez. Fark, C ++ 'da daha da belirgindir (sonucu sabitleyebilirsiniz, ancak out / ref parametresini oluşturamazsınız).
greenoldman

8
Çünkü python buna sahipti ve python, C # 'ın sahip olmadığı hiçbir şeye sahip olamaz;)
Evan Plaice

Yanıtlar:


117

Programları yazarken, bir sınıf oluşturmayı haklı çıkarmak için yeterli ortaklığa sahip olmayan bir dizi değeri mantıksal olarak bir araya getirmek istemek son derece yaygındır.

Birçok programlama dili, yalnızca tek bir şekilde bir tür oluşturmadan, normalde alakasız olan bir dizi değeri mantıksal olarak gruplamanıza izin verir:

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

Mantıksal olarak bu, 3-tuple int, string, double olan bir argüman alan M yöntemiyle tamamen aynıdır. Ama umarım gerçekten yapmazsınız:

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

MArguments'ın iş mantığında başka bir anlamı olmadığı sürece.

"Bir sınıftan daha hafif olan bazı yapılarda bir grup başka şekilde ilgisiz veriyi bir araya getirme" kavramı, yalnızca yöntemlerin biçimsel parametre listeleri için değil, birçok yerde yararlıdır. Bir yöntemin döndürülmesi gereken iki şey olduğunda veya bir sözlüğü bir yerine iki veriden kapatmak istediğinizde, vb. Yararlıdır.

Tuple türlerini yerel olarak destekleyen F # gibi diller, kullanıcılarına büyük bir esneklik sağlar; son derece kullanışlı bir veri türleri kümesidir. BCL ekibi, her dilin bunlardan faydalanabilmesi için çerçeve için tek bir demet türünü standartlaştırmak üzere F # ekibiyle birlikte çalışmaya karar verdi.

Bununla birlikte, bu noktada C # tuples için dil desteği yoktur . Tuples, diğer çerçeve sınıfları gibi yalnızca başka bir veri türüdür; onlar hakkında özel bir şey yok. C # 'ın varsayımsal gelecek sürümlerinde demetler için daha iyi destek eklemeyi düşünüyoruz. Herhangi birinin, ne tür özellikler görmek istediğinize dair herhangi bir fikri varsa, bunları tasarım ekibine iletmekten memnuniyet duyarım. Gerçekçi senaryolar teorik düşüncelerden daha ikna edicidir.


1
@MalcomTucker: Asychrony ve paralellik, gerçek sorunları çözmek için dil araçlarının kullanılabileceği zengin alanlar olarak kesinlikle aklımızda. F # tarzı eşzamansız iş akışlarının mutlaka C # için en uygun olduğunu düşünmüyorum, ancak kesinlikle ilham verici.
Eric Lippert

60
Demetler yararlı olsa da, büyük bir dezavantaj netliktir. Bu ifade eder kodunu okumak ve anlamak zor Item1, Item2küpe hiç C # dil desteğini elde yaparsanız, vb ..., onların üyeleri kod verir şekilde adlandırılmış (ya da en azından takma adlı) izin vermek için harika olacağını kullandığı daha anlaşılır olmaları için. Böyle varsayımsal bir gelecekte, bireysel parametreleri alan yöntemlerin yasal parametreleri olarak uygun "şekle" sahip demetleri görmeyi de çok isterim (ve tersi). Yani Tuple<int,string,bool>geçilebilir M(int,string,bool). Hatırlama yöntemlerini çok daha kolay hale getirir.
LBushkin

2
Bu "tuplelar" temelde tüm publicerişim, isimsiz üyelerin olduğu anonim struct türlerdir . Programcının , üyelerinin anlambilimiyle ilgili bana hiçbir şey söylemeyen bir ile uğraşmaktansa, adlandırılmış üyelerle bir yazıp geri göndermesini tercih ederim . structtuple
bobobobo

1
@ Hi-Angel: Tartışma, neyin bir demet olarak sayılıp neyin olmadığı konusunda tartışmakla ilgili değil, daha çok modern iş kolu geliştiricilerin üretkenliklerini artırmak için kullanabilecekleri özelliklerin ne olduğu ile ilgili . LBushkin, tasarım ekibinin her zaman duyduğu bir özellik talebini ifade ediyor: Sadece birkaç alanı bir arada tutmak için bütün bir sınıfı yapma zahmeti ve masrafı olmadan bir tür "kayıt türü" yapma arzusu. C # zaten yöntemler için bu özelliğe sahiptir; buna "parametre listesi" denir.
Eric Lippert

2
@ Hi-Angel: Muhtemelen "yöntem parametrelerinize ismiyle erişmek istiyorsanız ayrı bir sınıf oluşturmalısınız" argümanını yapmazsınız çünkü bu son derece ağır görünüyor, ancak sadece ağır görünüyor çünkü biz bir yöntemi çağırırken rastgele türler ve adlarla bir dizi rastgele değişkeni anında birbirine bağlama yeteneği . Hiçbir dilin bu özelliğe sahip olmadığını hayal edin; her yöntem yalnızca tek bir argüman alabilir ve ikisini geçmek istiyorsanız, bir tür oluşturup bunun bir örneğini iletmeniz gerekir.
Eric Lippert

22

Tuples, bir koleksiyonun değişmez bir uygulamasını sağlar

Tuple'ların ortak kullanımlarının yanı sıra:

  • bir sınıf oluşturmak zorunda kalmadan ortak değerleri gruplamak
  • bir işlevden / yöntemden birden çok değer döndürmek için
  • vb...

Değişmez nesneler, doğaları gereği iş parçacığı açısından güvenlidir:

Değişmez nesneler, çok iş parçacıklı uygulamalarda yararlı olabilir. Birden çok iş parçacığı, diğer iş parçacıkları tarafından değiştirilen verilerin endişesi olmadan değişmez nesnelerle temsil edilen veriler üzerinde hareket edebilir. Bu nedenle değişmez nesnelerin, değiştirilebilir nesnelerden daha iş parçacığı açısından güvenli olduğu düşünülmektedir.

Gönderen "Immutable Nesne" wikipedia


Soruya ek bilgi eklediğiniz için teşekkür ederiz. Çok minnettarım.
Chaddeus

Değişmez bir koleksiyon istiyorsanız, bir Tuple değil, değişmez bir koleksiyon kullanmalısınız. Fark en değişmez koleksiyonları için en elemanların sayısını belirtmek için derleme-vakit kalmamasıdır
Danny Pflughoeft - BlueRaja

@ BlueRaja-DannyPflughoeft Bu cevabı yazdığımda, C # değişmez koleksiyon sınıfları hala BCL'de mevcut değildi. MS C # kayıt düzeni uygulaması kısırlaştırılmış beri 'nesne' olarak 'koleksiyonunu' değiştireceğiz Tahmin
Evan Plaice

12

Yanıtının bir parçası olarak birden çok yeni nesne döndürmeniz gereken bir yönteminiz varsa refveya buna bir alternatif sağlar out.

Ayrıca, tek yapmanız gereken iki veya üç mevcut türü birleştirmekse ve yalnızca bu kombinasyon için bir sınıf / yapı eklemek istemiyorsanız, yerleşik bir türü dönüş türü olarak kullanmanıza da olanak tanır. (Bir işlevin anonim bir tür döndürebilmesini dilediniz mi? Bu, bu duruma kısmi bir yanıttır.)


Lanet olsun. Güzel. Keşke birkaç yıl önce ne olduğunu kontrol etseydim;).
sabiland



4

Şahsen, ben bir araştırma döngüsündeyken veya sadece "oynarken" Tuples'ı geliştirmenin yinelemeli bir parçası olarak görüyorum. Bir Tuple genel olduğundan, genel parametrelerle çalışırken bunu düşünme eğilimindeyim - özellikle genel bir kod parçası geliştirmek istediğimde ve kendime "bu çağrıyı nasıl isterim?" Diye sormak yerine kodun sonunda başlıyorum bakmak?".

Çoğunlukla Tuple formlarının bir listenin parçası haline geldiğini ve List> 'e bakmanın listenin amacını ya da nasıl çalıştığını gerçekten ifade etmediğini fark ediyorum. Sıklıkla onunla "yaşıyorum", ancak kendimi listeyi manipüle etmek ve bir değeri değiştirmek isterken buluyorum - bu noktada, bunun için mutlaka yeni bir Tuple oluşturmak istemiyorum, bu nedenle kendi sınıfımı veya yapımı oluşturmam gerekiyor tutmak için, böylece manipülasyon kodu ekleyebilirim.

Elbette, her zaman genişletme yöntemleri vardır - ancak çoğu zaman bu ekstra kodu genel uygulamalara genişletmek istemezsiniz.

Verileri bir Tuple olarak ifade etmek istediğim ve Tuple'ların mevcut olmadığı zamanlar oldu. (VS2008) bu durumda kendi Tuple sınıfımı oluşturdum - ve onu iş parçacığını güvenli (değişmez) yapmıyorum.

Bu yüzden, Tuples'ın amacını açıklayan bir tür adını kaybetme pahasına tembel programlama olduğunu düşünüyorum. Diğer masraf, parametre olarak kullanıldığı her yerde Tuple'ın imzasını beyan etmeniz gerektiğidir. Şişirilmiş görünmeye başlayan bir dizi yöntemden sonra, benim yaptığım gibi, yöntem imzalarını temizlerken bir sınıf oluşturmaya değer olduğunu hissedebilirsiniz.

Sınıfı, halihazırda çalışmakta olduğunuz sınıfın genel bir üyesi olarak başlama eğilimindeyim. Ancak, basitçe bir değerler koleksiyonunun ötesine geçtiği anda, kendi dosyasını alır ve onu içerdiği sınıfın dışına taşırım.

Geriye dönüp baktığımda, gidip bir sınıf yazmak istemediğimde Tuples'ı kullandığıma ve şu anda yazdıklarımı düşünmek istediğime inanıyorum. Bu, Tuple'ın imzasının, bu yöntem için hangi verilere ihtiyaç duyacağımı ve hangi değerleri geri getireceğini nasıl geri getireceğini bulurken, metinde yarım saat içinde epeyce değişebileceği anlamına gelir.

Kodu yeniden düzenleme şansım olursa, genellikle bir Tuple'ın içindeki yerini sorgularım.


3

2010'dan beri eski soru ve şimdi 2017'de Dotnet değişiyor ve daha akıllı hale geliyor.

C # 7, tuple'lar için yeni, daha verimli tuple türlerini kullanarak bir demetin alanları için anlamsal adlar sağlayan dil desteği sunar.

2017 ve .Net 4.7 sürümlerinde (veya nuget paketi System.ValueTuple'ı yükleyerek), çok verimli ve basit bir şekilde bir demet oluşturabilir / kullanabilirsiniz:

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

Bir yöntemden birden fazla değer döndürmek:

    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}");    

Daha fazla ayrıntı için şu adresi okuyun: https://docs.microsoft.com/en-us/dotnet/csharp/tuples


1

Tuple, belirli bir tür oluşturmak istemediğinizde genellikle işlevlerden birden çok değer döndürmek için kullanılır. Python'a aşina iseniz, Python bunu uzun zamandır kullanıyor.


1

Bir işlevden birden fazla değer döndürmek. getCoordinates (), yalnızca x veya y veya z döndürürse pek kullanışlı değildir, ancak tam bir sınıf ve nesnenin üç girişi tutması da oldukça ağır görünür.


1

Yaygın bir kullanım, yalnızca 2 alan içeren sınıflar / yapılar oluşturmaktan kaçınmak olabilir, bunun yerine bir Tuple (veya şimdilik bir KeyValuePair) oluşturursunuz. Bir dönüş değeri olarak kullanışlıdır, N parametresini geçmekten kaçının ...


0

Bir Dictionary'deki anahtar değer çiftlerini yinelemek için KeyValuePair'i C # 'da yenilenirken buluyorum.


KeyValuePairözel amaçlı bir çözüm olarak görülebilir. Python'da, dictsadece dönen (anahtar, değer) demetler üzerinde yineleme .
dan04

Evet, python gibi. :-) c # anahtarındaki KeyValuePair'in bir demet olmadığının farkında değildim?
Jubal

0

Fonksiyonlardan değer döndürürken gerçekten faydalıdır. Birden fazla değeri geri alabiliriz ve bu, bazı senaryolarda oldukça tasarrufludur.


0

Tuples ve Anahtar-Değer çiftleri arasındaki bu performans karşılaştırmasına rastladım ve muhtemelen bunu ilginç bulacaksınız. Özetle, Tuple'ın bir sınıf olduğu için avantaja sahip olduğunu, dolayısıyla yığında değil yığında saklandığını ve argüman olarak iletildiğinde göstericisinin giden tek şey olduğunu söylüyor. Ancak KeyValuePair bir yapı olduğundan ayırması daha hızlıdır ancak kullanıldığında daha yavaştır.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.