Equip 3rd party types with a deconstructor

08/04/2024
C#.NET

Deconstructor are a C# language feature that allows you to define a method that will be called when an object is being split up into its components. While this is straightforward to implement for your own types, it is not possible to add a deconstructor to a 3rd party type - or is it?

Deconstructor

Deconstructors are a C# language feature that allows you to define a method that will be called when an object is being split up into its components. Here is a very simple example:

public class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    public void Deconstruct(out int x, out int y)
    {
        x = X;
        y = Y;
    }
}

Which can then be called like this:

var point = new Point(3, 4);
var (x, y) = point;

Nice and easy, but your method needs the Deconstruct method to be defined. What if you want to deconstruct a 3rd party type that you cannot modify? Well, as many other features in C#, the compiler is your friend and can help you out. How? The compiler will look for a method with the signature Deconstruct in the type you are trying to deconstruct, but it will also look for an extension method with the same signature. This means that you can define a deconstructor for a 3rd party type by defining an extension method with the same signature. Here is an example:

public static class Extensions
{
    public static void Deconstruct(
        this Uri uri, 
        out string scheme,
        out string host,
        out string path,
        out string query,
        out string fragment)
    {
        scheme = uri.Scheme;
        host = uri.Host;
        path = uri.AbsolutePath;
        query = uri.Query;
        fragment = uri.Fragment;
    }
}

And then you can use it like this:

const string url = "https://steven-giesel.com/1?query=test#anchor";
var (scheme, host, path, query, fragment) = new Uri(url);

Console.WriteLine($"Scheme: {scheme}"); // https
Console.WriteLine($"Host: {host}"); // steven-giesel.com
Console.WriteLine($"Path: {path}"); // /1
Console.WriteLine($"Query: {query}"); // ?query=test
Console.WriteLine($"Fragment: {fragment}"); // #anchor

This is a more niche feature, and it is more convenient than a necessity. However, if you have a fixed set of properties you need from a type, this can be a very concise way to get them.

3
An error has occurred. This application may no longer respond until reloaded. Reload x