C# - ValueTuple

C# 7.0 (.NET Framework 4.7) introduced the ValueTuple structure, which is a value type representation of the Tuple.

The ValueTuple is only available in .NET Framework 4.7. If you don't see ValueTuple in your project, then you need to install the ValueTuple. (.NET Framework 4.7 or higher, or .NET Standard Library 2.0 or higher already includes ValueTuple.)

To install the ValueTuple package, right-click on the project in the solution explorer and select Manage NuGet Packages... This will open the NuGet Package Manager. Click the Browse tab, search for ValueTuple in the search box, and select the System.ValueTuple package, as shown below.

Use ValueTuple in C#

ValueTuple Initialization

It is easy to create and initialize the ValueTuple. It can be created and initialized using parentheses () and specifying the values in it.

var person = (1, "Bill", "Gates");
    
//equivalent Tuple
//var person = Tuple.Create(1, "Bill", "Gates");

The ValueTuple can also be initialized by specifying the type of each element, as shown below.

Example: ValueTuple
ValueTuple<int, string, string> person = (1, "Bill", "Gates");
person.Item1;  // returns 1
person.Item2;   // returns "Bill"
person.Item3;   // returns "Gates"

The following is a short way of declaring types for each member.

Example: ValueTuple

(int, string, string) person = (1, "James", "Bond");
person.Item1;  // returns 1
person.Item2;   // returns "James"
person.Item3;   // returns "Bond"

Note that we have not used var in the above tuple initialization statement; instead, we provided the type of each member values inside the brackets.

Tuple requires at least two values. The following is NOT a tuple.

var number = (1);  // int type, NOT a tuple
var numbers = (1,2); //valid tuple

Unlike Tuple, a ValueTuple can include more than eight values.

var numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); 

Named Members

We can assign names to the ValueTuple properties instead of having the default property names like Item1, Item2 and so on.

Example: Named Members of ValueTuple
(int Id, string FirstName, string LastName) person = (1, "Bill", "Gates");
person.Id;   // returns 1
person.FirstName;  // returns "Bill"
person.LastName; // returns "Gates"

We can also assign member names on the right side with values, as below.

var person = (Id:1, FirstName:"Bill", LastName: "Gates");

Please note that we can provide member names either on the left or right sides but not on both sides. The left side has precedence over the right side. The following will ignore names on the right side.

// PersonId, FName, LName will be ignored.
(int Id, string FirstName, string LastName) person = (PersonId:1, FName:"Bill", LName: "Gates");

// PersonId, FirstName, LastName will be ignored. It will have the default names: Item1, Item2, Item3.
(string, string, int) person = (PersonId:1, FName:"Bill", LName: "Gates");

We can also assign variables as member values.

string firstName = "Bill", lastName = "Gates";
var per = (FirstName: firstName, LastName: lastName);

ValueTuple as Parameter

The ValueType can also be a parameter type or return type of a method. The following method accepts a ValueTuple type parameter.

Example: ValueTuple As Parameter
static void Main(string[] args)
{
    DisplayTuple((1, "Bill", "Gates"));
}

static void DisplayTuple((int, string, string) person)
{
    Console.WriteLine("{0}, {1}, {2}", person.Item1, person.Item2, person.Item3);
}

The following returns a ValueTuple from the method.

Example: ValueTuple As Return Type
static void Main(string[] args)
{
    var person = GetPerson();
    Console.WriteLine("{0}, {1}, {2}", person.Item1, person.Item2, person.Item3);
}

static (int, string, string) GetPerson() 
{
    return (1, "Bill", "Gates");
}

You can also specify member names for a ValueTuple returned from the method.

Example: ValueTuple As Return Type
static void Main(string[] args)
{
    var person = GetPerson();
    Console.WriteLine("{0}, {1}, {2}", person.Id, person.FirstName, person.LastName);
}

static (int Id, string FirstName, string LastName) GetPerson() 
{
    return (Id:1, FirstName: "Bill", LastName: "Gates");
}

Deconstruction

Individual members of a ValueTuple can be retrieved by deconstructing it. A deconstructing declaration syntax splits a ValueTuple into its parts and assigns those parts individually to fresh variables.

Example: Deconstruct ValueTuple
static void Main(string[] args)
{
    // change property names
    (int PersonId, string FName, string LName) = GetPerson();
}
static (int, string, string) GetPerson() 
{
    return (Id:1, FirstName: "Bill", LastName: "Gates");
}

We can also use var instead of explicit data type names.

Example: Deconstruct ValueTuple
static void Main(string[] args)
{
    // use var as datatype
    (var PersonId, var FName, var LName) = GetPerson();
}
static (int, string, string) GetPerson() 
{
    return (Id:1, FirstName: "Bill", LastName: "Gates");
}

ValueTuple also allows "discards" in deconstruction for the members you are not going to use.

// use discard _ for the unused member LName
(var id, var FName, _) = GetPerson();