I decompiled some C# 7 libraries and saw ValueTuple
generics being used. What are ValueTuples
and why not Tuple
instead?
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Generic Generics in Managed C++
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
A
ValueTuple
is a struct which reflects a tuple, same as the originalSystem.Tuple
class.The main difference between
Tuple
andValueTuple
are:System.ValueTuple
is a value type (struct), whileSystem.Tuple
is a reference type (class
). This is meaningful when talking about allocations and GC pressure.System.ValueTuple
isn't only astruct
, it's a mutable one, and one has to be careful when using them as such. Think what happens when a class holds aSystem.ValueTuple
as a field.System.ValueTuple
exposes its items via fields instead of properties.Until C# 7, using tuples wasn't very convenient. Their field names are
Item1
,Item2
, etc, and the language hadn't supplied syntax sugar for them like most other languages do (Python, Scala).When the .NET language design team decided to incorporate tuples and add syntax sugar to them at the language level an important factor was performance. With
ValueTuple
being a value type, you can avoid GC pressure when using them because (as an implementation detail) they'll be allocated on the stack.Additionally, a
struct
gets automatic (shallow) equality semantics by the runtime, where aclass
doesn't. Although the design team made sure there will be an even more optimized equality for tuples, hence implemented a custom equality for it.Here is a paragraph from the design notes of
Tuples
:Examples:
You can easily see that working with
System.Tuple
becomes ambiguous very quickly. For example, say we have a method which calculates a sum and a count of aList<Int>
:On the receiving end, we end up with:
The way you can deconstruct value tuples into named arguments is the real power of the feature:
And on the receiving end:
Or:
Compiler goodies:
If we look under the cover of our previous example, we can see exactly how the compiler is interpreting
ValueTuple
when we ask it to deconstruct:Internally, the compiled code utilizes
Item1
andItem2
, but all of this is abstracted away from us since we work with a decomposed tuple. A tuple with named arguments gets annotated with theTupleElementNamesAttribute
. If we use a single fresh variable instead of decomposing, we get:Note that the compiler still has to make some magic happen (via the attribute) when we debug our application, as it would be odd to see
Item1
,Item2
.I looked at the source for both
Tuple
andValueTuple
. The difference is thatTuple
is aclass
andValueTuple
is astruct
that implementsIEquatable
.That means that
Tuple == Tuple
will returnfalse
if they are not the same instance, butValueTuple == ValueTuple
will returntrue
if they are of the same type andEquals
returnstrue
for each of the values they contain.This is a pretty good summary of what it is and its limitation
https://josephwoodward.co.uk/2017/04/csharp-7-valuetuple-types-and-their-limitations
In addition to the comments above, one unfortunate gotcha of ValueTuple is that, as a value type, the named arguments get erased when compiled to IL, so they're not available for serialisation at runtime.
i.e. Your sweet named arguments will still end up as "Item1", "Item2", etc. when serialised via e.g. Json.NET.
The difference between
Tuple
andValueTuple
is thatTuple
is a reference type andValueTuple
is a value type. The latter is desirable because changes to the language in C# 7 have tuples being used much more frequently, but allocating a new object on the heap for every tuple is a performance concern, particularly when it's unnecessary.However, in C# 7, the idea is that you never have to explicitly use either type because of the syntax sugar being added for tuple use. For example, in C# 6, if you wanted to use a tuple to return a value, you would have to do the following:
However, in C# 7, you can use this:
You can even go a step further and give the values names:
... Or deconstruct the tuple entirely:
Tuples weren't often used in C# pre-7 because they were cumbersome and verbose, and only really used in cases where building a data class/struct for just a single instance of work would be more trouble than it was worth. But in C# 7, tuples have language-level support now, so using them is much cleaner and more useful.
Other answers forgot to mention important points.Instead of rephrasing, I'm gonna reference the XML documentation from source code:
The ValueTuple types (from arity 0 to 8) comprise the runtime implementation that underlies tuples in C# and struct tuples in F#.
Aside from created via language syntax, they are most easily created via the
ValueTuple.Create
factory methods. TheSystem.ValueTuple
types differ from theSystem.Tuple
types in that:With introduction of this type and C# 7.0 compiler, you can easily write
And return two values from a method:
Contrary to
System.Tuple
you can update its members (Mutable) because they are public read-write Fields that can be given meaningful names: