I want to start by mentioning that C# already had support for anonymous types. Which are reference types. Thus, you already had a suitable alternative to creating a named class.
One advantage of a named class is the will be easier to reuse (for example if you need the same type in multiple places) and document. Since the anonymous type is anonymous, you can only get variables typed to it if you can use var
, which limits the contexts in which anonymous types are useful (for example, you can't use them as field types, return types or parameter types).
Of course, you could go over some of the limitations of anonymous types by using System.Tuple
. Which is also a reference type, and you can use it explicitly. The downside is that it lacks custom names for the members.
C# 7 tuples (ValueTuple
) can be considered similar to anonymous types. The first difference is that they are value types. This means that these tuples will have performance advantage as long as they stay in local scope or are moving across the stack (which is the common usage of anonymous types, due to its limitation).
The second difference is that the new syntax allows tuples to appear in more places than anonymous types, as you know, you have syntactic sugar to define the return type to ValueTuple
(while using anonymous types you had to return object
).
The third difference is that ValueTuple
supports deconstruction out of the box. To quote What’s New in C# 7.0:
Another way to consume tuples is to deconstruct them. A deconstructing declaration is a syntax for splitting a tuple (or other value) into its parts and assigning those parts individually to fresh variables:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
WriteLine($"found {first} {last}.");
Which you can also do with custom types by adding a Deconstruct method.
For abstract:
ValueTuple
has syntactic sugar in C# 7.0, which should be considered for readability.
ValueTuple
is a value type. All pros and cons between the use of a class
and a struct
apply.
ValueTuple
can used explictly (with or without the syntactic sugar) allowing it to have the versatility of System.Tuple
while retaining named members.
ValueTuple
supports deconstruction.
Given that must of it is syntactic sugar, I would say that the stronger argument to choose ValueTuple
is the same argument to choose a struct
. Which would be ideal for small, immutable types, that live mostly on the stack (so you do not have lots of boxing and unboxing).
Comparing ValueTuple
against a full blown struct, considering the syntactic sugar, I would suggest to use ValueTuple
by default, unless you need an explicit layout or you need to add methods to it.
I also want to say that the syntactic sugar does not necessarily improve readability. The main reason being that you are not naming the type, and the name of the type provides meaning to the code. In addition of that, you can add documentation to a struct
or class
declaration that eases understanding.
All in all, the situation where ValueTuple
really shines is returning multiple values from a method. In this case removing the need of creating new out
parameters. And the documentation of the ValueTuple
used can live in the documentation of the method. If you find you need to do something else with the ValueTuple
(defining extension methods for example), I would suggest to consider creating a named type instead.