C# Tuple – How to use Tuples in C#

A tuple is a lightweight data structure that provides concise syntax to group multiple data elements. In this article, I will show you how to work with a C# tuple.

Ever been in need to pass multiple values around at the same time? By using a C# Tuple we can do just that – but with a little warning. Tuples can be hard to understand and use. When I first started using Tuples I asked myself: how are the values inside a tuple related? How can we place our data in a tuple into variables in the code that has meaningful names?

If you like me, create software and need a quick way to move data around, this guide will help you to do that by teaching you how to add tuples to your own project the right way.

If you are ready to get started with C# tuples and learn to get them working under the hood of your application, then let’s move on.

Is C# Tuple the same as System.Tuple?

When I started using tuples, I got confused by the two. A C# tuple is not the same as System.Tuple. System.Tuple makes use of a class and a C# tuple is backed by System.ValueTuple.

As I just mention, System.Tuple are classes, where System.ValueTuple are structs. The great thing about using a ValueTuple is that it is mutable and not “read-only” like a System.Tuple is. The members of System.ValueTuple are fields, where System.Tuple are properties (because of the class).

If you are using C# 7 or later, I would recommend you to use System.ValueTuple. If you are using an older version, then you are forced to use System.Tuple. I will show you how to use both of them in this article – don’t worry.

When to use a Tuple?

A tuple is perfect for moving data around in your application, without having to create a new model/class to hold your data.
The most common cases where I use tuples are:
– When I need to group related values.
– When I have to return multiple values from a function without using the out parameter.
– When I do LINQ projection. (When I need to extract a subset of elements from a sequence of data).

What is a Tuple in C#?

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.

Using System.Tuple

System.Tuple is a tuple implementation that makes use of classes. This was the defacto standard prior to C# 7 – which is the reason why it’s widely used in many “old” applications. Lots of developers still use it.

Type arguments with System.Tuple

The old tuple classes require type arguments. When you create new tuples you must provide them using the new constructor. The number and types of tuple members are determined på the type arguments, hence they are important.

Below is an example of a tuple with two members of string type:

Tuple<string, string> names = new Tuple<string, string>("Christian", "Schou");

If you create a new tuple without specifying the type of arguments in the constructor, your compiler will return an error. Here is an example:

Tuple<string, string> names = new Tuple("Christian", "Schou");

Compilation error: Cannot create an instance of the static class 'System.Tuple'

Tuple.Create() – Why not just use new?

When working with System.Tuple, we got two options for creating tuples. Tuple.Create() and new Tuple(). So what is the difference? There is no difference… I prefer to use Tuple.Create() because I find it more concise and it makes my code easier to read for other developers including myself in the future when I have to come back and refactor something.

var names = Tuple.Create("Christian", "Schou"); // How I normally do it - easier to write

var names = new Tuple<string, string>("Christian", "Schou"); // Less concise

The core difference between the two is that you don’t have to specify your argument types when using Tuple.Create(). As I mentioned earlier, you will get a compiler error, if you don’t specify the argument types when using the new constructor.

If you take a look at the code behind it, you will see that both ways actually do the same thing. When you use Tuple.Create() it will call the Tuple() constructor with a set of default values.

Below is an example of how the two of them are doing the same job using generic arguments.

public static class Tuple
{
    public static Tuple<T1, T2, etc...> Create<T1, T2, etc...>(T1 item1, T2 item2, etc...) {
        return new Tuple<T1, T2, etc...>(item1, item2, etc...);
    }
}

How to access data in System.Tuple?

When you create a new tuple and want to access the data inside it (your values) you only have to specify the item you would like the value for. Elements in System.Tuple does not make use of names, instead, you have to use an ordinal index to access the values in your tuple.

var address = Tuple.Create("H.C. Andersen Haven 1", "Odense C", 5000, "Denmark");

string street = address.Item1; // H.C. Andersen Haven 1
string city = address.Item2 // Odense C
int zip = address.Item3 // 5000
string country = address.Item4 // Denmark

How to update the value of a System.Tuple member?

It’s easy – you cant. System.Tuple is immutable. Once it’s created, you cannot change it. If you try to do it, you will end up with a compiler error.

var carPrice = Tuple.Create("Mercedes EQE", 96726.60);

carPrice.Item2 = 88876.99; 

// Compilation error: Property or indexer 'Tuple<string, double>.Item2' cannot be assigned to -- it is read only

If you need to update the value, you would have to destroy and re-create the tuple with the new value you would like to have in the tuple:

var carPrice = Tuple.Create("Mercedes EQE", 96726.60);

Tuple.Create(carPrice.Item1, 88876.99);

Using C# Tuple (System.ValueTuple) – Since C# 7

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.

My favorite and the one I always use if possible. The C# Tuple is a comma-separated list of values enclosed in parentheses. With this type, we can have nested tuples + values counting from 0 to many.

Tuple types - C# reference
Learn about C# tuples: lightweight data structures that you can use to group loosely related data elements

A C# tuple since C# 7 has the following syntax.

(double, int) t1 = (4.5, 3);
Console.WriteLine($"Tuple with elements {t1.Item1} and {t1.Item2}.");
// Output:
// Tuple with elements 4.5 and 3.

(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.

How to declare a C# Tuple?

I always use names when specifying my tuples, to make the code easier to read and maintain. The ultimate easier method is just by using the parentheses syntax though.

In the example above you can see both ways to declare the tuples.

How to update a C# tuple value?

Opposite of System.Tuple, a C# tuple is mutable. The developers behind C# changed the new kind of tuples to be implemented as a ValueTuple which is a struct, that we are able to update.

It is very easy to update a tuple at runtime. We only have to specify the new value for the element in the tuple. An example is shown below of how you can accomplish that task.

var latLong = (55.39594, 10.38831); // Odense coordinates

latLong.Item1 = 55.05982;
latLong.Item2 = 10.60677;

Console.WriteLine(latLong); // (55.05982, 10.60677) - Svendborg coordinates

How to use Named Tuples

By default, each member of your tuple is constructed with a name like “item1”, “item2”, “item3”, etc… Whenever I see someone do that in C# 7 or later, I decline the pull request with a comment telling them to update the tuple with the naming of the members because it is harder to read the code for other developers resulting in a codebase that’s harder to maintain in the future. PLEASE use named tuples whenever possible!

Since C# 7 a new type of tuple has been introduced – “named tuple”. A named tuple can have named members – which makes the code easier to write and maintain.

Below is an example of how to create a named tuple based on the example above with coordinates.

(double latitude, double longitude) coordinates = (55.39594, 10.38831);

Console.WriteLine(coordinates); // (55.39594, 10.38831)

Console.WriteLine(coordinates.latitude); // 55.39594

Console.WriteLine(coordinates.longitude); // 10.38831

How to do tuple deconstruction?

Ever wondered how you could extract the value of a named tuple by creating a method? Tuple deconstruction is a nice feature that allows us to extract values from a tuple into separate variables.

C# got a special syntax we can use to deconstruct a C# tuple to get the value of the members. To deconstruct a C# tuple, you actually just have to use the same syntax as when you initially created the C# tuple.

Below is an example of how you can extract the city name from a tuple, with this format: (string, string, int, string). The only thing you have to do is call the method GetCity and pass the tuple to it:

public static string GetCity((string, string, int, string) cityName)
{
  (_, string, _, _) = cityName; 

  return cityName;
}

var address = ("H.C. Andersen Haven 1", "Odense C", 5000, "Denmark");

Console.WriteLine(GetCity(address)); // Odense C

The underscore(s) “_” is present because we would like to ignore the other values. We only want value number two (index 1) – the city from the C# tuple.

Tuple vs Enum and Dictionary

A tuple is very often used instead of an enum since enums in C# don’t support string values. I have made an example below to show you what I mean:

public enum StatusCodes
{
  New = "A new order has been received",
  Shipped = "The order has been shipped from the warehouse",
  Delivered = "The order has been delivered to the customer"
}

If we told our compiler to build this you would get a compiler error. The reason is that enums only support numeric values, hence tuples are a good idea to use. This would be a solution:

List<(string ShortStatus, string LongStatus)> statusCodes = new List<(string ShortStatus, string LongStatus)>() 
{ 
  ("New", "A new order has been received"), 
  ("Shipped", "The order has been shipped from the warehouse"),
  ("Delivered", "The order has been delivered to the customer")
};

Console.WriteLine(statusCodes[0].LongStatus); // A new order has been received

If you normally would you a dictionary, I would advise you to switch to C# tuples as they often are more concise.

You might be thinking – are they not quite the same? In some way. A dictionary like this: Dictionary<TKey, TValue> is a way to structure data into key-value pairs. You are able to store any type and any value you would like. The only problem is that you can only store one value per key. If you were using tuples, you would be able to store multiple values using the same key.

That’s why I often use a C# tuple instead of a dictionary.

Summary

In this article, we have taken a look at both types of tuples in the .NET ecosystem. A c# tuple is a great way to parse and return multiple values to/from a method without having to create a new model. Tuples can be difficult to understand, so please use them with caution.

Tuples should not be used in all cases. I got a rule of thumb that goes like this: If I got less than three items I will use a tuple to move data around. If you got more items, please create a class as they are easier to maintain and add a standard for that specific type of data.

I hope you learned some new programming techniques from this article. If you got any issues, questions, or suggestions, please let me know in the comments. Happy coding!

You've successfully subscribed to Tech with Christian
Great! Next, complete checkout to get full access to all premium content.
Error! Could not sign up. invalid link.
Welcome back! You've successfully signed in.
Error! Could not sign in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.