A Quick Look at Multiple Return Values
One of my favorite features that was added in C# 7 was support for multiple variable assignment from return values via the use of Tuples. Here’s a quick example of a function that declares multiple return values.
public (Article[] articles, string[] tags) FindArticles(DateTimeOffset begin, DateTimeOffset end)
{
// query data ...
return (articles, tags);
}
And calling it would then look like…
(var articles, var tags) = FindArticles(begin, end);
The alternatives to this prior to C# 7 would be either to declare a class to wrap the values into a single return type, to create out parameters, or else to make multiple function calls (e.g. FindArticles/FindTags…).
The new C# 7 syntax provides a nice clean symmetry between the return type declaration and the assignment statement. Under the hood, the C# compiler is using System.ValueTuple to represent the return values. If you’re targeting a .NET Framework version earlier that 4.7 or targeting NET Standard 1.x, then you’ll need to add a reference to the ValueTuple NuGet package.
As with most new language features, there are a few caveats to consider.
- First, the multiple return values feature should not replace proper modelling or DTOs. Think of it more as a garnish to mix into your existing code to make certain calls (or combination of calls) more convenient. For example, it can eliminate some of the “throw away” types that are created simply for returning groups of objects together.
- Currently, it is recommended that multiple return value use is kept internal to a library or application and that is not be used as part of its public interface. Consider a scenario where you would have to work with a library from an earlier version of C#, and having to deal with the ValueTuple directly is not so useful.
- There is extra work needed to make C# 7 work with ASP.NET projects hosted on the .NET Framework (especially if you are upgrading an older existing project). You will need to make sure the ASP.NET CodeDom compiler NuGet package for ASP.NET is installed (a.k.a. Microsoft.CodeDom.Providers.DotNetCompilerPlatform), which will in turn bring in the Roslyn compiler NuGet package (Microsoft.Net.Compilers). Be careful here! If your target environment uses the 4.5.x runtime, then the highest compatible version of Microsoft.Net.Compilers is 1.3.2, which effectively limits you to C# 6. NuGet may automatically bring in the latest 2.x Roslyn compiler package, which will lead to compilation errors once you deploy your app to the 4.5.x running server (been there, got the T-shirt.)
Deconstructing to Multiple Variable Assignment
The formal term for the assignment of multiple discrete variables from a return value is called Deconstruction. While the syntax shown above utilizes tuples, C# 7 allows other types to be used for multiple assignment as well. Deconstruction provides a compact syntax for assigning variables from values contained in an object. It also somewhat bridges the gap between allowing the new C# syntax to be used with a function while keeping that function backwards compatible with C# 6 and earlier consumers (see the final example in this post). Support for deconstructing an existing type can be added via a convention method named Deconstruct and giving the method one or more out parameters.
As an example, let’s wrap up the return values from the first example into a new type.
public class FindArticlesResult
{
public Article[] Articles;
public string[] Tags;
public void Deconstruct(out Article[] articles, out string[] tags)
{
articles = Articles;
tags = Tags;
}
}
The FindArticles method is then updated as follows…
public FindArticlesResult FindArticles(DateTimeOffset begin, DateTimeOffset end)
{
// query data ...
return new FindArticlesResult()
{
Articles = articles,
Tags = tags
};
}
From C# 7 it can be called with the same syntax as before.
(var articles, var tags) = FindArticles(begin, end);
// NOTE: multiple assignment can be done from an existing variable as well.
var result = FindArticles(begin, end);
(var articles, var tags) = result;
From C# 6 and earlier, the result can be accessed directly.
var result = FindArticles(begin, end);
var articles = result.Articles;
var tags = result.Tags;
That’s all for now! Be sure to check out the great documentation on docs.microsoft.com that covers Tuples and Deconstruction in more detail.
Comments
Comments are closed