In C# you have some built-in support for deconstructing system types and for non-supported scenarios, you can always extend your types to support that. Let’s see how to deconstruct types in C#.
Tuples have support for deconstruction which lets you unpackage all their items in a single operation.
Here is an example with and without deconstruction:
public static void Main()
{
var result = QueryCityData("New York City");
// Without deconstruction:
var city = result.Item1;
var pop = result.Item2;
var size = result.Item3;
// With deconstruction:
(string city, int population, double area) = QueryCityData("New York City");
}
private static (string city, int population, double area) QueryCityData(string name)
{
return (name, 8175133, 468.48);
}
You may be interested in the values of only some elements.
You can take advantage of C#’s support for discards, which are variables whose values you ignore by using the underscore character.
Using the previous example:
public static void Main ()
{
// city and population were discarded.
(, , double area) = QueryCityData("Portugal");
}
Other system types and deconstruction
Here are some system types that implement deconstruction, such as dictionary entries:
Dictionary<string,int> customerToTaxMapping = new Dictionary<string, int>();
foreach ((string key, int taxId) in customerToTaxMapping)
{
// Do something with key and taxId
}
You can deconstruct KeyValuePair instances (depending on your C# version, was introduced in .NET Core 2.0):
(string id, string taxId) = new KeyValuePair("id", "taxId");
If you are on C# 12 (.NET 8), then you can make use of the Deconstruct methods for DateTime, DateOnly and DateTimeOffset:
(DateOnly date, TimeOnly time) = new DateTime(2023, 1, 2, 4, 5, 59, 999);
(int year, int month, int day) = new DateTime(2023, 1, 2);
(int year, int month, int day) = new DateOnly(2023, 5, 1);
// Instantiate date and time using years, months, days,
// hours, minutes, seconds and a time span.
(DateOnly date, TimeOnly time, TimeSpan offset) = new DateTimeOffset(2008, 5, 1, 8, 6, 32, new TimeSpan(1, 0, 0));
Deconstruct user-defined types:
You can add public methods named Deconstruct and specify the out parameters that will define the parameters you want when applying deconstruction.
public class Person
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public void Deconstruct(out string firstName, out string lastName)
{
firstName = FirstName;
lastName = LastName;
}
public void Deconstruct(out string id, out string firstName, out string lastName)
{
id = Id;
firstName = FirstName;
lastName = LastName;
}
}
If you don’t have control over the types that you want to provide deconstruction support for, then you can create a static class with a Deconstruct extension method with the same signature as displayed previously, for that given type.
Additionally, when you declare a record type by using two or more positional parameters, the compiler creates a Deconstruct method within the record declaration.
Note: You can’t deconstruct dynamic objects.
References:
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/deconstruct
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#127-deconstruction