|<<>>|4 of 323 Show listMobile Mode

Swift protocol extensions for C#

Published by marco on

 Extension syntax in C#14Since this feature is being touted for C# 14—this time it’s coming for real!—I thought it would be good to refresh what I’d already learned about it. The title is a bit hyperbolic but it’s quite an interesting feature. It’s basically protocol extension from Swift for C#. It’s .NET’s answer to extending extension methods to properties and, probably, operators. You can’t add state, as far as I can tell. But that isn’t so surprising.

The video below discuss the proposal as it looked for C#13. The pages What’s new in C# 14: Extension members and Extension declaration (C# Reference) offer more insight into the current shape of the feature. It seems like they mean it this time and that it will land in November 2025.

The Insane C# 13 Feature That Changes Everything by Nick Chapsas (YouTube)

What it primarily is, though, is further work on making it easier to transition APIs. We got the first batch of support with default interface implementations. This feature will allow to smooth migrations even more. They will also allow us to “add” properties to types that then introduce their own version of those properties in future versions but that’s OK, I think. It means that every added property will be a potential breaking change for someone but maybe it will make us start categorizing breaking changes.

There are implicit extensions, which are pretty much a new way of defining extension methods, but with support for proprties. The following example shows how the property IsLead will be available for any Person without modifying that type. This doesn’t seem much different than existing extension methods, other than support for properties, where the this keyword stands in for the parameter that would otherwise have been passed in a classic extension method.

public implicit extension PersonExtension for Person
{
    public bool IsLead
        => this.Organization
            .Teams
            .Any(team => team.Lead == this);
}

There are also explicit extensions, which are a way of specifying extensions to types that are neither implemented nor inherited, but are instead given to a type without coercion. That is, you can define a type that can be applied to another type (e.g., Lead for Person in the example below), which makes more methods and properties available. It’s kind of confusing without an example.

public explicit extension Lead for Person
{
    public IEnumerable<Team> Teams 
        => this.Organization
            .Teams
            .Where(team => team.Lead == this);
}

var person = new Person();
var personTeams = person.Teams; // Compile error
Lead lead = person;
var leadTeams = lead.Teams; // OK

While this might look like a cast, it’s not, because Person doesn’t implement Lead—it’s extended by Lead in code that isn’t necessarily associated with the code that defines Person.

In the latest syntax, the example above would look a bit different but the idea is the same. It looks like they’ve simplified it a bit.

public static class PersonExtension
{
    extension(Person source)
    {
        public bool IsLead
        => source.Organization
            .Teams
            .Any(team => team.Lead == this);;
    }
}