A tuple tÃpus a .NET 4.5 változatában mutatkozott be, de tényleges nyelvi elemeket, amikkel univerzális nyelvi elemmé vált, csak a C# 7.x változatban kapott.
A tuple tÃpus egy, vagy több adattag tárolására szolgáló generikus objektum. Leginkább arra találták ki, hogy ha kettÅ‘, vagy három adattagot össze kell fogni, akkor ne kelljen azok tárolására kódba egy új osztályt bevezetni.
Tuple tÃpusokból két fajta létezik: az érték és a referencia alapú.
Referencia tuple
A referencia alapú változatok megtalálhatóak a .NET 4.5-ben is és nem különösebben rendelkeznek nyelvi támogatással. Az alábbi példa egy két elemű tuple létrehozását mutatja be:
var tuple = new Tuple<int, int>(11, 22);
Mint láthatjuk, ez egy generikus osztály, ami elemek tárolásra szolgál. Az egyes tárolt elemeket az ItemN tulajdonságokkal érhetjük el a kódon belül, ahol N a tulajdonság száma. Ezek indexelése 1-től indul.
var tuple = new Tuple<int, int>(11, 22);
var x = tuple.Item1; //11
var y = tuple.Item2; //22
A legnagyobb problémája ennek a tÃpusnak, hogy az egyes tagváltozók nem nevezhetÅ‘ek el értelmes módon, Ãgy a kódban igencsak nehézkes a használatuk.
Érték tuple
Itt jön be az érték tuple, ami struct alapú. Ennek több elÅ‘nye is van. A legnagyobb CLR szempontbeli elÅ‘ny, hogy az egyenlÅ‘ség és a másolás kérdése egyszerűbb, feltéve, hogy a létrehozott tuple tÃpusunk egyszerű tÃpusokból épül fel és nem komplex, egyedi osztályokból. Itt megjegyezném, hogy ilyen célra nem alkalmas, nem ajánlott a tuple használata.
Viszont ha tényleg csak pár tÃpust kell összefognunk egy objektumba, akkor igen hasznos tud lenni. Érték alapú tuple tÃpust a következÅ‘képpen tudunk létrehozni:
var tuple = (11, 22);
var x = tuple.Item1; //11
var y = tuple.Item2; //22
Az egyes elemeket el is nevezhetjük, amivel később hivatkozni tudunk rájuk:
var tuple = (X: 11, Y: 22);
var X = tuple.X; //11
var X = tuple.Y; //22
Ha metódus argumentumban vagy visszatérési értékben szeretnénk alkalmazni tuple tÃpusokat, akkor megadhatjuk a mezÅ‘k tÃpusát és nevét is:
(int X, int Y) Duplaz((int X, Int Y) bemenet)
{
return (X*2, Y*2);
}
Tuple Deconstruct
Tételezzük fel, hogy van egy egyedi osztályunk, amit szeretnénk érték tuple tÃpusba konvertálni. Ebben az esetben egyedi konverziós metódusok helyett elég az osztályunkat kiegészÃteni egy Deconstruct metódussal, ami out paraméterek sorozataként visszaadja az osztály mezÅ‘it. Deconstruct metódusból akár többet is definiálhatunk.
class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public void Deconstruct(out int X, out int Y)
{
X = this.X;
Y = this.Y;
}
}
Point p = new Point(11, 22);
//Deconstruct hÃvódik
//width értéke a P.X lesz
//height értéke P.Y lesz
var (width, height) = p;
A Deconstruct metódusok extension metódusként is definiálhatóak:
class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
}
static class Extension
{
public static void Deconstruct(this Point point, out int X, out int Y)
{
X = point.X;
Y = point.Y;
}
}
Point p = new Point(11, 22);
//Deconstruct hÃvódik
//width értéke a p.X lesz
//height értéke p.Y lesz
var (width, height) = p;