It is very common to be carrying out a process or service and need to return multiple results from a method.
A very common practice is to create a private class which will only be used in that method, so it might not be the best solution.
To solve this problem, .NET provides us with Tuples, which have been available since .NET Framework 4.0. However, despite being very useful, many developers do not even know they exist.
Later, we will see an improvement of it with ValueTuple
.
1 - What is a Tuple?
When we refer to a Tuple, we are talking about a data structure that can contain multiple types.
As I have explained, it is ideal for when we want to keep multiple data but we don't want to create a class just for that.
The syntax for a Tuple
is as follows:
Tuple<T1>
...
Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>
As you can see, the element limit is 8, and it's also immutable.
At first glance, it might look similar to the dynamic type, but unlike that, in tuples your types are strongly typed.
Finally, note that a tuple is a reference type, so it is allocated on the heap.
1.1 - Creating a tuple in C#
In C#, we can create tuples in two ways:
A. Specifying the generic types in the constructor
Tuple<string, string, int> coche
= new Tuple<string, string, int>("Audi", "A3", 2008);
B. Using the static method Create
that C# provides, allowing us not to have to specify the tuple types, which can become tedious if we have several.
var coche2 = Tuple.Create("Opel", "Astra", 2005);
Technically you can create a tuple inside another tuple, but personally, I've never needed to do so, and I have my doubts that it's a good idea, as it will make your code less readable.
1.2 - Accessing elements of a tuple
To access each element of the tuple, we use Item<ElementNumber>
.
For example, in our example we have three properties, so we access them with:
coche.Item1;
coche.Item2;
coche.Item3;
Which allows us to do something like the following:
Tuple<string, string, int> coche
= new Tuple<string, string, int>("Audi", "A3", 2008);
var coche2 = Tuple.Create("Opel", "Astra", 2005);
Console.WriteLine($"El primer coche es un {coche.Item1} {coche.Item2} del año {coche.Item3}");
Console.WriteLine($"El segundo coche es un {coche2.Item1} {coche2.Item2} del año {coche2.Item3}");
1.3 - Passing Tuples as parameters
A use we can give it is to pass multiple elements to a method in a single parameter.
void PrintMessage(Tuple<string, string, int> coche){
Console.WriteLine($"El coche es un {coche.Item1} {coche.Item2} del año {coche.Item3}");
}
1.4 - Returning Tuples from a method
The most common use of tuples is to return multiple values from a method, and it lets us do so in a very simple and clear way. We simply declare Tuple<T>
as the return type and it works without problems:
Tuple<string, string, int> CalculateCar3()
{
return Tuple.Create("Ford", "Fiesta", 1995);
}
2 - What is ValueTuple?
After releasing Tuple<T>
, Microsoft realized that it was good, but there was room for improvement, so in C#7 they introduced the ValueTuple
structure, which is a value representation of a tuple.
2.1 - Initializing ValueTuple in C#
Initializing a ValueTuple
object is very simple, just indicate the values between parentheses ()
:
(string, string, int) moto1 = ("Derbi", "Variant", 1980);
As we can see, it's very similar to Tuple
, but with much less syntax.
2.2 - Accessing ValueTuple elements
To access the elements, we do the same as with the tuple, using Item<ElementNumber>
.
Console.WriteLine($"la moto es una {moto1.Item1} {moto1.Item2} del año {moto1.Item3}");
But that is not the only option, because when we use ValueTuple
we can assign a name or alias to the variables. This is very important because it makes our code much easier to understand.
(string marca, string modelo, int year) moto2 = ("Bultaco", "Lobito", 1998);
Console.WriteLine($"la moto es una {moto2.marca} {moto2.modelo} del año {moto2.year}");
As you can see, instead of using Item1, Item2, and Item3
we have used the aliases we declared.
2.3 - ValueTuple as a return type
Just like with tuples, the most common use for ValueTuple is as a return type, or when we pass it as a parameter to a method.
As you can see, it's very similar to what we saw before:
(string, string, int) CalculateBike3(){
return ("Honda", "CBR", 2005);
}
void PrintBikeMessage((string marca, string modelo, int year) moto)
{
Console.WriteLine($"la moto es una {moto.marca} {moto.modelo} del año {moto.year}");
}
2.4 - Deconstructing a ValueTuple object
Alternatively, we can individually receive multiple values from a ValueTuple
by using the deconstructor
.
What does this mean? It means we can assign a ValueTuple
directly to multiple individual variables:
(string bikeBrand3, string bikeModel3, int bikeYear3) = CalculateBike3();
Console.WriteLine($"la moto es una {bikeBrand3} {bikeModel3} del año {bikeYear3}");
As you can see, we're using the variable bikeBrand3
and not a property inside an object.
- Note: If you do not want to use one of the properties, you can always use
_
to discard it.
Conclusion
- In this post we have seen what Tuples and ValueTuple are in C# and how to work with them.
- It is recommended to use tuples when you want to return multiple values from a method, as this allows us to avoid using
ref
orout
. - Additionally, we can pass multiple elements in a single parameter.
- Don't forget, we also have limitations, such as only being able to contain 8 elements.
If there is any problem you can add a comment bellow or contact me in the website's contact form