Jakie wymaganie miała rozwiązać krotka?


94

Patrzę na nową funkcję C # krotek. Jestem ciekawy, jaki problem miał rozwiązać krotka?

Do czego używasz krotek w swoich aplikacjach?

Aktualizacja

Dzięki za dotychczasowe odpowiedzi, zobaczę, czy mam pewne sprawy w głowie. Jako współrzędne wskazano dobry przykład krotki. Czy to wygląda dobrze?

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

Następnie użyj krotki w ten sposób:

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

Czy to jest poprawne?



4
Cóż, przychodzą mi do głowy dwie odpowiedzi ...
Noon Silk

13
Jeśli pojęcie „współrzędnych” ma sens jako klasa, to uczyniłbym z tego klasę. Stosować krotki dla tych sytuacjach, w których istnieje nie jakiś sensowny „logiki biznesowej” koncepcja zestawu danych, które uzasadniają dokonanie typu.
Eric Lippert

13
Współrzędne nie są dobrym przykładem krotki. Krotka w C # jest po prostu rozwiązaniem ad hoc w przypadkach, gdy trzeba zwrócić (z funkcji) dwie wartości. Zamiast ustawiać jeden typ wyniku plus jeden parametr wyjściowy, bardziej eleganckie jest zwrócenie jednej krotki. Dzięki temu nie musisz wcześniej deklarować drugiego parametru. Różnica jest jeszcze wyraźniejsza w C ++ (możesz const wynik, ale nie możesz const parametru out / ref).
greenoldman

8
Ponieważ python to miał, a python nie może mieć niczego, czego nie ma C #;)
Evan Plaice

Odpowiedzi:


117

Podczas pisania programów niezwykle często występuje chęć logicznego zgrupowania zestawu wartości, które nie mają wystarczającej wspólności, aby uzasadnić utworzenie klasy.

Wiele języków programowania pozwala na logiczne grupowanie razem zestawu niepowiązanych ze sobą wartości bez tworzenia typu tylko w jeden sposób:

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

Logicznie rzecz biorąc, jest to dokładnie to samo, co metoda M, która przyjmuje jeden argument, który jest 3 krotką typu int, string, double. Ale mam nadzieję, że tak naprawdę nie zrobiłbyś:

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

chyba że MArguments miał inne znaczenie w logice biznesowej.

Koncepcja „grupowania razem zbioru niepowiązanych w inny sposób danych w pewną strukturę, która jest lżejsza niż klasa” jest przydatna w wielu, wielu miejscach, nie tylko w przypadku formalnych list parametrów metod. Jest to przydatne, gdy metoda ma dwie rzeczy do zwrócenia lub gdy chcesz wyodrębnić słownik z dwóch danych zamiast jednej, i tak dalej.

Języki, takie jak F #, które natywnie obsługują typy krotek, zapewniają użytkownikom dużą elastyczność; są niezwykle użytecznym zestawem typów danych. Zespół BCL zdecydował się współpracować z zespołem F # w celu ujednolicenia jednego typu krotki dla frameworka, tak aby każdy język mógł z nich skorzystać.

Jednak w tym momencie nie ma obsługi języka dla krotek w C #. Krotki to po prostu inny typ danych, jak każda inna klasa frameworka; nie ma w nich nic specjalnego. Rozważamy dodanie lepszej obsługi krotek w hipotetycznych przyszłych wersjach języka C #. Jeśli ktoś ma jakieś przemyślenia na temat tego, jakie funkcje związane z krotkami chciałbyś zobaczyć, z przyjemnością przekażę je zespołowi projektowemu. Realistyczne scenariusze są bardziej przekonujące niż rozważania teoretyczne.


1
@MalcomTucker: Asychronia i paralelizm są zdecydowanie w naszych umysłach jako bogate obszary, w których narzędzia językowe mogą być używane do rozwiązywania rzeczywistych problemów. Nie sądzę, że asynchroniczne przepływy pracy w stylu F # są koniecznie najlepiej dopasowane do języka C #, ale zdecydowanie są inspirujące.
Eric Lippert

60
Chociaż krotki są przydatne, jedną dużą wadą jest przejrzystość. Trudno jest odczytać i zrozumieć kod, który odnosi się do Item1, Item2itp ... Jeśli krotki kiedykolwiek osiągną wsparcie językowe w C #, byłoby cudownie pozwolić swoim członkom na nadawanie nazw (lub przynajmniej aliasów) w sposób, który pozwala na kod używający aby były bardziej zrozumiałe. W takiej hipotetycznej przyszłości chciałbym również zobaczyć krotki o odpowiednim „kształcie” jako prawne parametry metod, które przyjmują indywidualne parametry (i odwrotnie). Więc Tuple<int,string,bool>można przekazać M(int,string,bool). To znacznie ułatwiłoby zapamiętywanie metod.
LBushkin

2
Te „krotki” to w zasadzie wszystkie typy publicdostępu, anonimowe struct typy z nienazwanymi członkami . Wolałbym, żeby programista napisał a structz nazwanymi członkami i zwrócił to, niż mieć do czynienia z elementem tuple, który nie mówi mi nic o semantyce swoich członków.
bobobobo

1
@ Hi-Angel: Argument nie dotyczy sporów o to, co liczy się jako krotka, a co nie, ale raczej o zestaw funkcji, które nowocześni programiści mogą wykorzystać do zwiększenia swojej produktywności . LBushkin wyraża prośbę dotyczącą funkcji, którą zespół projektowy słyszy przez cały czas: chęć stworzenia pewnego rodzaju „rekordu” bez kłopotów i kosztów tworzenia całej klasy, aby zebrać razem kilka pól. C # ma już tę funkcję dla metod; nazywa się to „listą parametrów”.
Eric Lippert

2
@ Hi-Angel: Prawdopodobnie nie przedstawiłbyś argumentu „jeśli chcesz uzyskać dostęp do parametrów metody według nazwy, powinieneś utworzyć osobną klasę”, ponieważ wydaje się to bardzo ciężkie, ale wydaje się ciężkie tylko dlatego, że jesteśmy przyzwyczajeni do posiadania możliwość natychmiastowego powiązania zestawu dowolnych zmiennych z dowolnymi typami i nazwami podczas wywoływania metody . Wyobraź sobie, że żaden język nie miał takiej cechy; każda metoda może przyjąć tylko jeden argument, a jeśli chcesz przekazać dwa, musisz utworzyć typ i przekazać jego instancję.
Eric Lippert

22

Krotki zapewniają niezmienną implementację kolekcji

Oprócz typowych zastosowań krotek:

  • grupowanie wspólnych wartości bez konieczności tworzenia klasy
  • aby zwrócić wiele wartości z funkcji / metody
  • itp...

Niezmienne obiekty są z natury bezpieczne wątkowo:

Niezmienne obiekty mogą być przydatne w aplikacjach wielowątkowych. Wiele wątków może działać na danych reprezentowanych przez niezmienne obiekty bez obawy o zmianę danych przez inne wątki. Dlatego niezmienne obiekty są uważane za bardziej bezpieczne dla wątków niż obiekty zmienne.

Z „Immutable Object” na Wikipedii


Dziękujemy za dodanie dodatkowych informacji do pytania. Bardzo cenione.
Chaddeus

Jeśli chcesz niezmienną kolekcję, powinieneś użyć niezmiennej kolekcji, a nie krotki. Różnica polega na tym, że w przypadku większości niezmiennych kolekcji nie musisz określać liczby elementów w czasie kompilacji
BlueRaja - Danny Pflughoeft

@ BlueRaja-DannyPflughoeft Kiedy pisałem tę odpowiedź, niezmienne klasy kolekcji C # nadal nie były dostępne w BCL. Chyba zmienię „kolekcję” na „obiekt”, ponieważ MS wykastrowało implementację Tuple w C #
Evan Plaice

12

Stanowi alternatywę reflub outjeśli masz metodę, która musi zwrócić wiele nowych obiektów w ramach swojej odpowiedzi.

Pozwala również na użycie typu wbudowanego jako typu zwracanego, jeśli wszystko, co musisz zrobić, to połączyć dwa lub trzy istniejące typy i nie chcesz dodawać klasy / struktury tylko dla tej kombinacji. (Czy kiedykolwiek chciałeś, aby funkcja mogła zwrócić typ anonimowy? To jest częściowa odpowiedź na tę sytuację.)


Cholera. Ładny. Żałuję, że kilka lat temu nie sprawdziłem, czym są krotki;).
sabiland



4

Osobiście uważam, że krotki są iteracyjną częścią rozwoju, gdy jesteś w cyklu badawczym lub po prostu „grasz”. Ponieważ krotka jest ogólna, myślę o niej podczas pracy z parametrami ogólnymi - szczególnie gdy chcę opracować ogólny fragment kodu i zaczynam od końca kodu, zamiast zadawać sobie pytanie „jak chciałbym to wywołanie patrzeć?".

Dość często zdaję sobie sprawę, że kolekcja, którą tworzy krotka, staje się częścią listy, a wpatrywanie się w List> tak naprawdę nie wyraża intencji listy ani tego, jak ona działa. Często z tym „żyję”, ale mam ochotę manipulować listą i zmieniać wartość - w tym momencie niekoniecznie chcę tworzyć nową krotkę, dlatego muszę utworzyć własną klasę lub strukturę aby go zatrzymać, więc mogę dodać kod manipulacji.

Oczywiście zawsze istnieją metody rozszerzające - ale dość często nie chcesz rozszerzać tego dodatkowego kodu na implementacje ogólne.

Czasami chciałem wyrazić dane jako krotka i nie miałem dostępnych krotek. (VS2008) w takim przypadku właśnie utworzyłem własną klasę Tuple - i nie ustawiam jej jako bezpiecznej dla wątków (niezmiennej).

Myślę więc, że jestem zdania, że ​​krotki są leniwym programowaniem kosztem utraty nazwy typu, która opisuje jego przeznaczenie. Innym kosztem jest to, że musisz zadeklarować podpis krotki, gdziekolwiek jest ona używana jako parametr. Po kilku metodach, które zaczynają wyglądać na rozdęte, możesz poczuć, tak jak ja, że ​​warto utworzyć klasę, ponieważ czyści ona sygnatury metod.

Zwykle zaczynam od publicznego członka klasy, w której już pracujesz. Ale w momencie, gdy wykracza poza zwykły zbiór wartości, pobiera swój własny plik i przenoszę go z klasy zawierającej.

Z perspektywy czasu wydaje mi się, że używam krotek, gdy nie chcę wychodzić i pisać zajęć, a po prostu chcę pomyśleć o tym, co piszę teraz. Co oznacza, że ​​podpis krotki może się bardzo zmienić w tekście przez pół godziny, podczas gdy ja zastanawiam się, jakich danych będę potrzebować dla tej metody i jak zwraca wszystkie wartości, które zwróci.

Jeśli dostanę szansę na refaktoryzację kodu, często będę kwestionować miejsce w nim krotki.


3

Stare pytanie od 2010 roku, a teraz w 2017 Dotnet zmienia się i staje się bardziej inteligentny.

C # 7 wprowadza obsługę języka dla krotek, co umożliwia nazwy semantyczne pól krotki przy użyciu nowych, bardziej wydajnych typów krotek.

W porównaniu z 2017 i .Net 4.7 (lub instalując pakiet NuGet System.ValueTuple) możesz tworzyć / używać krotki w bardzo wydajny i prosty sposób:

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

Zwracanie więcej niż jednej wartości z metody:

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

Aby uzyskać więcej informacji, przeczytaj: https://docs.microsoft.com/en-us/dotnet/csharp/tuples


1

Krotka jest często używana do zwracania wielu wartości z funkcji, gdy nie chcesz tworzyć określonego typu. Jeśli znasz Pythona, Python ma to od dawna.


1

Zwracanie więcej niż jednej wartości z funkcji. Funkcja getCoordinates () nie jest zbyt użyteczna, jeśli zwraca tylko x, y lub z, ale utworzenie pełnej klasy i obiektu do przechowywania trzech liczb całkowitych również wydaje się dość ciężkie.


1

Typowym zastosowaniem może być unikanie tworzenia klas / struktur, które zawierają tylko 2 pola, zamiast tego można utworzyć Tuple (lub na razie KeyValuePair). Użyteczna jako wartość zwracana, unikaj przekazywania N parametrów ...


0

Odnajduję KeyValuePair odświeżania w C #, aby wykonać iterację nad par klucz-wartość w słowniku.


KeyValuePairmożna postrzegać jako obejście specjalnego przeznaczenia. W Pythonie iteracja po krotkach dictzwraca (klucz, wartość).
dan04

Tak, jak Python. :-) Nie wiedziałem, że KeyValuePair w c # nie jest krotką?
Jubal

0

Jest to bardzo pomocne podczas zwracania wartości z funkcji. Możemy odzyskać wiele wartości, co w niektórych scenariuszach jest dość oszczędne.


0

Natknąłem się na ten test porównawczy wydajności między krotkami i parami klucz-wartość i prawdopodobnie uznasz to za interesujące. Podsumowując, mówi, że Tuple ma przewagę, ponieważ jest klasą, dlatego jest przechowywana w stercie, a nie w stosie, a kiedy jest przekazywana jako argument, jedyną rzeczą, która się dzieje, jest jej wskaźnik. Ale KeyValuePair to struktury, więc alokacja jest szybsza, ale wolniejsza, gdy jest używana.

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.