Introduction

Let’s talk about one of the cool new features of C# 7.0 - deconstruction. Quite often you might need to return more than one value from a method, which can be accomplished in several ways:

  • use out/ref arguments (usually considered a code smell)
  • create a more meaningful class/struct that represents the result of calling the method (a preferable option, especially as the number of returned values grows)
  • use System.Tuple (some kind of a middleground)

They all work, but in fact only a special return type feels like a good solution, since both out arguments and explicitly used tuples look just like a boilerplate code and don’t contribute to readable code.

Update 2017-04-09: As pointed out by Julien Couvreur in the comments, I made some incorrect conclusions about how compiler actually deconstructs ValueTuples. I assumed that this is done using the extensions methods in the System.ValueTuple NuGet package, while they are clearly declared on the older System.Tuple type and are NOT being used for the deconstruction. In fact, C# compiler has built-in knowledge for ValueTuple type, so no extensions needed. More detailed explanation is available in this document in Roslyn repository on Github.

Before C# 7.0

As an example, I’ll use a very simple GetPositiveNumber method, which generates a random integer in the [-3, 3] interval and returns both the number and a boolean flag, specifying whether the nuber was actually positive. In previous versions of C#, if we followed the common Try... method pattern, it could look like this (imagine all of the following code to be inside a class):

Rewritten with tuples, it would look not too different (but at least without out arguments):

Not too bad. It already shows the intent of the code much better: clearly, the method returns two things packed into a container type. But when we try to write the code that calls this method, it begins to look ugly:

These Item1 and Item2 properties don’t really mean anything to the reader, they describe neither purpose, nor type. And this is exactly the problem that was solved with ValueTuple and deconstruction in C# 7.0.

Deconstruction

What really felt wrong in the previous version of our code is that we could not give the tuple properties meaningful names and also we needed to first assign the tuple itself to a variable and only after that we could access the values. If you think about it, this is redundant: we are not interested in the tuple itself, we just want our values! So, C# 7.0 allows us to write the same functionality in a much shorter way:

(IMPORTANT: for this to work, you need to manually install a System.ValueTuple NuGet package to your project, since the compiler will use types from it.)

This way both values we are actually interested in are immediately assigned to the corresponding variables - all in one line! Also, the method signature now reads much better, since it is quite obvious that there are two return values.

After 12 years of .NET development, this looks like magic. And I don’t like magic. So, if you are like me, the next thing you do is open your favourite IL disassembler (mine is ILSpy) and see what actually happens behind the scenes.

So, essentially everything we wrote was just syntactic sugar, which then was turned into using a concrete System.ValueTuple struct. We can also see that the method is now marked with a TupleElementNames attribute, which kept the names of the values returned by the original method. Obviously, we can deconstruct to local variables with any names, so this information is only preserved for displaying an Intellisense hint, when you hover over the method:

If we look at ValueTuple<T1,T2> itself, there is nothing really interesting, just a struct with (again!) Item1 and Item2 properties:

So, how does this struct get assigned to two variables at once? Turns out, the compiler will use duck-typing and check if there is Deconstruct method available on the type we are, well, deconstructing. Actually, the method doesn’t have to be defined in the type itself, it can be declared as an extension method - which is exactly the case for System.ValueTuple:

Finally, the magic is revealed! The C# compiler will convert our nice and readable code into a bit more boring code using ValueTuple, and if there is a deconstruction statement used in the calling code, it will be rewritten with the Deconstruct method, if such exists.

Edit 2017-04-09: Turns out I was wrong here (thanks to Julien Couvreur for correcting me): C# compiler has built-in knowledge of System.ValueTuple type, and moreover, the extensions methods above are clearly defined on a completely different type and have nothing to do with C# deconstruction syntax.

This bring us to another interesting question: can we only use deconstruction with these value tuples or with custom types as well?

Deconstructing custom types

Since we already saw that deconstruction works by using duck-typing, you can guess that the same trick works with our custom return types too. When might this be useful? Imagine you already have some method that returns a class, not a tuple, and you still want to leverage the deconstruction pattern when calling this existing method. Most likely you wouldn’t want to rewrite the method to use tuples (too much work probably) - and luckily you don’t have to! Just defining an extension method Deconstruct on the return type is enough to make compiler happy:

This is, in my opinion, the best way to write this kind of code, since we managed to combine the best of both worlds: the method now returns a type with a meaningful name (and can easily be extended with more properties, if necessary), while, with the help of an extension method, we could deconstruct the result into two local variables - still in one line.

Summary

One shouldn’t underestimate such language improvements: even though there is, strictly speaking, no new functionality here, it greatly reduces the amount of boilerplate code and improves redability by making the intent of a method much clearer. After all, human time is the most expensive resource in software development, so having less lines of code to read (without sacrificing readability) is a big win.