Tuples
- tuples provides concise syntax to group multiple data elements in a lightweight data structure.
- tuples, which are backed by
System.ValueTuple
are value types. - Data members of
System.ValueTuple
types are fields. - You can define tuples with an arbitrary large number of elements:
Simple
var person = ("siva", 30);
Console.WriteLine(person.Item1);
Console.WriteLine(person.Item2);
Specifying Data Types
(string, int) person = ("siva", 30);
Console.WriteLine(person.Item1);
Console.WriteLine(person.Item2);
Using Field Names
On Left Side
(string name, int age) person = ("siva", 30);
Console.WriteLine(person.name);
Console.WriteLine(person.age);
On Right Side
var person = (Name: "siva", Age: 30);
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
Using Variables
var name = "siva";
var age = 30;
var person = (name, age);
Console.WriteLine(person.name);
Console.WriteLine(person.age);
Using Classes
var person1 = new ValueTuple<string, int>("siva", 30);
var person2 = ValueTuple.Create<string, int>("ganesh", 20);
Usage
Tuples are commonly used in four ways:
- To represent a single set of data. For example, a tuple can represent a database record, and its components can represent individual fields of the record.
- To provide easy access to, and manipulation of, a data set.
- To return multiple values from a method without using out parameters (in C#) or ByRef parameters (in Visual Basic).
- To pass multiple values to a method through a single parameter.
Method Parameter
public static void DisplayPerson((string Name, int Age) person)
{
Console.WriteLine($"{person.Name} is {person.Age} years old");
}
DisplayPerson(("siva", 30));
Method Return Type
Only Type
public static (string, int) GetPerson()
{
return ("siva", 30);
}
var person = GetPerson();
Console.WriteLine(person.Item1);
Console.WriteLine(person.Item2);
With field names
public static (string name, int age) GetPerson()
{
return ("siva", 30);
}
var person = GetPerson();
Console.WriteLine(person.name);
Console.WriteLine(person.age);
Deconstruction
- C# features built-in support for deconstructing tuples, which lets you unpackage all the items in a tuple in a single operation.
(string name, int age) = GetPerson();
var (name, age) = GetPerson();
(var name, var age) = GetPerson();
Using existing variables
string name;
int age;
(name, age) = GetPerson();
Discard
- You can discard as many values as you like; all are represented by the single discard,
_
.
(string name, _) = GetPerson();
Equality
- Tuple assignment and tuple equality comparisons don't take field names into account.
Same names
var person1 = (name: "siva", age: 30);
var person2 = (name: "siva", age: 30);
Console.WriteLine(person1 == person2); //true
Different names
var person1 = (name: "siva", age: 30);
var person2 = (fullName: "siva", age: 30);
Console.WriteLine(person1 == person2); //true
Different values
var person1 = (name: "siva", age: 30);
var person2 = (name: "kumar", age: 30);
Console.WriteLine(person1 == person2); //false
Assignment
C# supports assignment between tuple types that satisfy both of the following conditions:
- both tuple types have the same number of elements
- for each tuple position, the type of the right-hand tuple element is the same as or implicitly convertible to the type of the corresponding left-hand tuple element
(int, double) t1 = (17, 3.14);
(double First, double Second) t2 = (0.0, 1.0);
t2 = t1;
Alias
- Beginning with C# 12, you can specify an alias for a tuple type with a using directive.
- An alias doesn't introduce a new type, but only creates a synonym for an existing type.
// declare outside the class
using Point = (int X, int Y);
// use inside method
Point p1 = (10, 20) ;
Console.WriteLine(p1.X);
Console.WriteLine(p1.Y);
Limitations of The ValueTuple
- Named-parameter feature of ValueTuples is just syntactic sugar to help with the readability and simplicity of our code.
- Named parameters do not have a runtime representation, which means that under the hood, the C# compiler is going to revert the custom names we have given the elements to Item1, Item2, etc.
- This has two main implications.
- First, we cannot access our named parameters via reflection.
- Secondly, if we cast a ValueTuple with named parameters to a dynamic type, trying to access the result elements using their custom names is going to give us a RuntimeBinderException because the system does not recognize those names anymore.
System.Tuple
- System.Tuple types are reference types.
System.Tuple
types are immutable.- Data members of
System.Tuple
types are properties. - You can create tuples of eight or more elements by nesting tuple objects in the Rest property of a Tuple<T1,T2,T3,T4,T5,T6,T7,TRest> object.
var person1 = new Tuple<string, int>("siva", 30);
var person2 = Tuple.Create<string, int>("siva", 30);
References:
- https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples
- https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/deconstruct
- https://learn.microsoft.com/en-us/dotnet/standard/base-types/choosing-between-anonymous-and-tuple
- https://learn.microsoft.com/en-us/dotnet/api/system.tuple?view=net-8.0
- https://code-maze.com/csharp-valuetuple-vs-tuple/
- https://code-maze.com/csharp-tuple/
- https://www.syncfusion.com/blogs/post/working-with-tuple-in-csharp.aspx