Tuple jest strukturą danych, która pozwala agregować w jednym obiekcie kilka elementów o dowolnych typach. Zobrazujmy to przykładem:
var parameters = new Tuple<int, string, DateTime>(2, "siemano", new DateTime(2000, 1, 1));
Innym sposobem na stworzenie obiektu klasy Tuple jest użycie metody Tuple.Create:
var parameters = Tuple.Create(2, "siemano", new DateTime(2000, 1, 1));
W przykładzie widzimy Tuple, który przechowuje w sobie trzy elementy - inta, stringa i obiekt daty. Możemy się do nich odwołać w ten sposób:
var number = parameters.Item1; var text = parameters.Item2; var date = parameters.Item3;
Dostęp do poszczególnych elementów Tuple jest więc bardzo mało elegancki i nic nie mówi nam o prawdziwym przeznaczeniu pól Tuple. Nie wiemy, czy pierwszy element - liczba - jest ilością czegoś, czyimś wiekiem czy może numerem strony w książce. Jest to poważna wada Tuple.
Tuple ograniczony jest do ośmiu elementów. Próba utworzenia Tuple z większą ilością pól zakończy się błędem kompilacji. Jest to kolejny spory problem z Tuple:
var parameters = Tuple.Create(1, 2, 3, 4, 5, 6, 7, 8, 9); //błąd kompilacji
Tuple mają więc poważne wady:
- poszczególne elementy nazywają się Item1, Item2, co absolutnie nic nie mówi czytającemu
- możemy mieć maksymalnie 8 elementów w Tuple (możemy oczywiście mieć Tuple zagnieżdżone. Moim zdaniem podniesie to wady Tuple do potęgi)
- Tuple nie posiada sensownej nazwy. Agregując w nim na przykład dane osoby takie jak wiek, imię i adres, tylko z kontekstu możemy domyślić się że Tuple reprezentuje osobę. Gdybyśmy użyli klasy lub struktury, ich nazwa wyjaśniałaby wszystko
- Tuple, w przeciwieństwie do struktury czy klasy, jest typem dość prymitywnym. Nie możemy go rozszerzać o metody, stosować dziedziczenia (jak w klasach) czy implementować interfejsów (jak zarówno w klasach, jak i strukturach)
int parsedNumber; var didParseSuccessfully = int.TryParse("11", out parsedNumber);
Moim zdaniem zarówno Tuple, jak i out są dość brzydkimi rozwiązaniami i powinny być używane w ostateczności. W przypadku funkcji TryParse uważam, że out jest mniejszym złem - pozwala nam bowiem uniknąć koszmarnych "Item1", "Item2".
Zamiast takiego kodu:
public void PrintPersonData(string name, string lastname, int age) { Console.WriteLine($"Imię: {name}, nazwisko: {lastname}, wiek: {age}"); }
Powinniśmy napisać:
struct Person { public string Name { get; set; } public string LastName { get; set; } public int Age { get; set; } } class Program { public void PrintPersonData(Person person) { Console.WriteLine($"Imię: {person.Name}, nazwisko: {person.LastName}, wiek: {person.Age}"); } }
Podsumowując:
Kiedy używać Tuple? Moim zdaniem najlepiej ich unikać. Tuple są mało czytelne i nie komunikują jasno co właściwie w sobie przechowują.
Ich użycie mogłoby być zasadne w takich przypadkach jak przechowywanie odczytanych rekordów z bazy, dla których nie chcemy tworzyć osobnej struktury danych w naszej aplikacji - ponieważ chcemy je przeorganizować, obciąć czy rozszerzyć, zanim zapiszemy je w instancjach klas czy struktur. Wtedy Tuple może posłużyć jako rodzaj tymczasowej struktury danych. Jeśli decydujemy się na użycie Tuple, miejmy na uwadze jak mało mówiąca jest to struktura i zastanówmy się, czy sami chcielibyśmy się domyślać, co reprezentuje Item1.
Od C# 7 dostępna jest nowa klasa: ValueTuple. Więcej o niej można przeczytać tutaj [under construction].
Komentarze
Prześlij komentarz