In this article, we are going to deconstruct the concept of Tuple in C#.

To download the source code for this article, you can visit our GitHub repository.

Let’s dive in.

What is Tuple in C#

Tuple in C# is a reference-type data structure that allows the storage of items of different data types. It comes in handy when we need to create an object that can hold items of different data types but we don’t want to create a completely new type.

Tuple initially appeared in .NET framework 4.0 and it can contain up to seven elements plus one optional TRest property as the eighth element Р(Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>). The TRest property is mostly for extension purposes and can hold a nested tuple object.

Tuple should not be mistaken for ValueTuple, which has been introduced as an improvement in C#7. We’re going to talk about the differences a bit later on.

First, let’s have look at how we can use Tuples in C#.

How To Use Tuples in C#

We can create tuples in two ways. Using the class-based approach and using the Tuple.Create() method.

How to Create a Tuple Using the Class-Based Syntax in C#

We can create a Tuple by using the Tuple class constructor and adding the actual elements that we can store in the Tuple within parentheses:

var tupleWithOneElement = new Tuple<string>("code-maze");

var tupleWithTwoElements = new Tuple<string, int>("code-maze", 24);

var tupleWithFiveElements = new Tuple<bool, int, string, decimal, string>
(true, 3, "CSharp", 23M, "john-doe");

With the class-based syntax, we have to explicitly declare the type of elements that we can store in the Tuple.¬† When we create a tuple with this syntax, the eighth item must be a nested tuple or we’ll get a run-time exception.

How to Create a Tuple Using the Tuple.Create Method in C#

The Tuple class contains a static Create method which returns a tuple object:

var tupleCreatedWithExplicitType = Tuple.Create<string>("code-maze"); 

var tupleCreatedWithNoExplicitType = Tuple.Create("code-maze"); 

var tupleWithTwoItems = Tuple.Create("code-maze", 24);

var tupleWithFiveItems = Tuple.Create(true, 3, "code-maze", 23M, "blockchain");

var tupleWithEightElements = Tuple.Create(true, "between", "zero", "and", "one" , false, "bezao", 24);

When we use the Create method, declaring the type of the Tuple elements is optional, as we can see in  tupleCreatedWithNoExplicitType and tupleCreatedWithExplicitType.

Unlike with the class-based syntax, using elements other than a nested tuple as the eighth item does not cause a run-time exception.

The items in a Tuple can be dynamic data types like arrays:

var tupleContainingArrays = Tuple.Create(new int[] { 1, 2, 3 }, new string[] { "black", "white" });

How to Create a Nested Tuple in C#

Trying to create a tuple with more than eight elements will result in a compile-time exception. To extend a tuple so that it contains more than eight items, we can nest another tuple in it. The nested tuple should be the last item in the sequence of elements.

The main reason for this is so that it can be accessed using the Rest property:

var nestedTuple = Tuple.Create("my", "name", "is", "john", "doe", "and", "I",
    Tuple.Create("am", 1000, "years", "old", true));

How To Access a Tuple and Nested Tuple in C#

We can access the elements of a tuple with the Item<n> property of a tuple, where “n” represents the index where the element appears in the tuple:

var tupleWithEightElements = Tuple.Create(true, "between", "zero", "and", "one" , false, "bezao", 24);

var itemOne = tupleWithEightElements.Item1; //returns true
var itemTwo = tupleWithEightElements.Item2; //returns "between" 
var itemSeven = tupleWithEightElements.Item7; //return "bezao"

To access the eighth item or the nested tuple we use the Tuple.Rest property and this returns a tuple. When we want to access the actual value we are going to use the Tuple.Rest.Item1 property: 

var itemEight = tupleWithEightElements.Rest; //returns (24)
var itemEightValue = tupleWithEightElements.Rest.Item1; //returns 24

Let’s see how we can access elements in a nested tuple:

var evenNumbers = Tuple.Create(2, 4, 6, 8, 10, 12, 14, 
Tuple.Create(16, 18, 20, 22, 24, 26));

var restItem = evenNumbers.Rest.Item1; //returns (16, 18, 20, 22, 24, 26)
var restItemElementOne = evenNumbers.Rest.Item1.Item1; //returns 16
var RestItemElementTwo = evenNumbers.Rest.Item1.Item2; //returns 18

We can also have more than one nested tuple inside a tuple:

var multipleNestedTuple = Tuple.Create(Tuple.Create(2, 4, 6, 8, 10), Tuple.Create(1, 3, 5, 7, 9),
Tuple.Create(4, 9, 16, 25, 36));

var multipleNestedTupleItemOne = multipleNestedTuple.Item1.Item1; //returns 2
var multipleNestedTupleItemTwo = multipleNestedTuple.Item2.Item1; //returns 1
var multipleNestedTupleItemThree = multipleNestedTuple.Item3.Item5; //returns 36

If we’re ever in a situation like this, we probably need to introduce classes.

Why Do We Need Tuples in C#?

Tuple class is important because it allows us to join elements of potentially various data types into a single object without having to create a custom class. 

Return Multiple Values Using Tuple in C#

We can return multiple values from a method without using the ref or out arguments or creating a custom type:

public static Tuple<bool, string, int[]> ReturnATuple(int num)
{
    var isEven = num % 2 == 0;

    var message = isEven ? $"{num} This number is even" : $" {num}This number is odd";

    var multiplesOfNum = new int[5];

    for (var x = 1; x <= 5; x++)
    {
        multiplesOfNum.Append(x * num);
        Console.WriteLine(x * num);
    }

    return Tuple.Create(isEven, message, multiplesOfNum);
}

ReturnATuple(24); //returns (true, 24 this number is even, int32[]) 

Pass Multiple Values To A Method Using Tuple in C#

We can pass multiple values to a method as a single unit:

public static string TakeInATuple(Tuple<int, bool> tuple)
{
    var hasAtLeastFourLegs = tuple.Item1 >= 4;
    var isBlue = tuple.Item2;

    return $"hasAtLeastFourLegs : {hasAtLeastFourLegs} and isBlue : {isBlue}";
}
 
TakeInATuple(Tuple.Create(10, true)); //returns "hasAtLeastFourLegs : true and isBlue : true"

Having seen how useful Tuples can be, we need to tackle some potential downsides of Tuples as well.

Potential Problems with Tuples pre C# 7

Tuples are very useful constructs in C#, but using them comes with some problems.

A Tuple is a reference-type object. After creation, a Tuple is read-only. We cannot change its size or edit its elements or their values. Reference-type objects have their memory allocated on the heap. To make any change, we are going to have to create a new tuple and allocate more memory on the heap. This can result in CPU-intensive operations and major performance issues in our system.

Another problem is it can only hold a maximum of eight elements. This setup forces us to use nested tuples when we want to include more elements or extend the length of the tuple. This creates a syntax that can be confusing.

Finally, there is no way to rename the individual elements of a tuple to better describe their values. In terms of accessing a tuple, we are only allowed to use the Tuple.ItemNumber property and it can get more complex when we want to access tuples with complex levels of nested tuples in them.

Recent Improvements to Tuples in C# 7 onward – ValueTuple

From C# 7 onward, System.ValueTuple was introduced. ValueTuple is essentially an upgraded version of the Tuple class. Some of its features are:

  • It’s a value-type object¬†
  • Can contain multiple elements
  • It is mutable
  • We can name the individual items of a ValueTuple
For an in-depth analysis of the differences between ValueTuple and Tuple and how to convert a Tuple to a ValueTuple, feel free to check our article.

Let’s summarize what we’ve learned.

Conclusion:

In this article, we looked at how to create and access tuples. We also looked at why we utilize tuples in C#.  Finally, we looked at potential drawbacks and enhancements of the Tuple class.