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);;
}
}
- There a talk called What’s new in C# 13 by Mads Torgersen and Dustin Campbell (Microsoft Build) for which you have to register. The video will probably come out later on YouTube, though.
- There’s the original [Proposal]: Extensions #5497 (GitHub)
- The most informative link (so far) is .NET Announcements and Updates from Microsoft Build 2024 by .NET Team (Microsoft Dev Blogs)