Using Value Tuple
All of us write methods that return one value, string method return a string, int method return an int, but what do you do when you need to return more than one value? Of course, you could create a container like class/struct, anonymous type or using out parameters.
Using anonymous type provides a way to return a set of properties using a single object without having to explicitly define a type. There's not support from intellisense, you need to remember the property name and type and even compiler can't find errors if accidentally you switched fields.
The solution with the out parameters does not wrap results in an single returned object, is a mix by value and by reference (out) parameters. It's a reasonable solution but should not be abused.
Classes help in these cases and are widely used in all applications, but it may happen that you eventually use them for everything, even when the complexity is low, new classes are created by adding small pieces that differ in only a few attributes or, in some cases, are a simple composition of several entities. This affects the code base, especially when you have to group heterogeneous elements.
Microsoft introduced a new way, first with Tuples and then with ValueTuples in C# 7, to support developer in these scenarios. If you are using that version or later, you can use them by installing System.ValueTuple from the NuGet package.
Tuples are great for moving data around allowing you to bind together items that might be of different types, for example, if I want to return some properties of the Currency Entity from a method without returning the whole instance, I could do like this:
public class Currency{public int Id { get; set; }public string Name { get; set; }public bool IsActive { get; set; }[...]}internal class Program{static void Main(string[] args){// Not only assigning multiple variables, but declaring them as well.var (name, isActive) = GetSomeDataFromCurrency(int currencyId);System.Console.WriteLine($"Currency {name} status is {isActive}.");}static (string Name, bool IsActive) GetSomeDataFromCurrency(int id){// Get the Currency, do some stuff and return valuesreturn (currency.Name, currency.IsActive);}}
But I think they are super useful for combining values that do not have much in common with each other without creating small custom classes every time (used only in that spot) or using one or more out parameters. For example, starting with a Country and Currency objects that have a bunch of properties, as defined below:
public class Currency{public int Id { get; set; }public string Name { get; set; }public bool IsActive { get; set; }[...]}public class Country{public int Id { get; set; }public string Name { get; set; }public string Language { get; set; }public int Population { get; set; }[...]}
For some reason I need to combine the two objects and as the below example shows, the DoSomeWithCountryAndCurrency method has the returning items types that appear in a set of brackets, both in the method declaration and as part of the return statement. Tuple has three items, CountryName, Population and CurrencyName values and they are sorted. You can deconstruct a Tuple instance in separate variables, or in other ways (tuples have several other additional syntax possibilities).
internal class Program{static void Main(string[] args){// Not only assigning multiple variables, but declaring them as well.var (countryName, population, currencyName) = DoSomeWithCountryAndCurrency(currencyId, countryId);System.Console.WriteLine($"{countryName} has {population} citizens and has {currency} as currency.");}static (string CountryName, int Population, string CurrencyName) DoSomeWithCountryAndCurrency(int country, int currency){// Do some stuff and return valuesreturn (country.Name, country.Population, currency.Name);}}
Conclusion
Tuples are an ordered sequence of (heterogeneous) elements and as said before are used when a method has to return more than one values. Basically, it's a convenient way to handle data in situations where building a custom class is overkill. You should consider a Tuple based, seems to me to be very flexible approach and can provide a variety of uses.
Happy coding!
Alberto