C# Advent 2025 - Extension Members
Hero image credit: Image generated by AI
This is my contribution to the 2025 C# Advent
Donny, the head of Elf IT, has a problem. Liza wrote a basic app to maintain data about the various workshops across Santa Toys Global Manufacturing & Distribution, Ltd., but then she quit and didn’t leave any source code. All Donny has is some documentation and a copy of the compiled class library. As best he can tell, it’s got a couple of classes that look something close to this.
public class Workshop
{
public List<Kid> NiceList = new List<Kid>();
public List<Kid> NaughtyList = new List<Kid>();
public int PresentsMade = 0;
public int PresentsPerNiceKid = 1;
public int LumpsOfCoalInReserve = 0;
}
public class Kid
{
public string Name { get; set; }
public int Age { get; set; }
}
Sure, he could rewrite that, but the library also has a bunch of other functionality that would take him too long to rewrite. And he’s under a lot of pressure to improve their IT systems performance. Then Donny remembers about extension methods.
Extension methods are nothing new. They’ve been around in .NET forever. If you aren’t familiar with them, extension methods allow you to add methods to an existing type or class without having to create a new derived type. Creating them is fairly straightforward. You create a static class, and add a static function to that class whose first parameter was the type to be extended with a “this” modifier, like so:
public static class MyExtensions
{
public static string MineCoal(this Workshop workshop, int amountMined){
workshop.LumpsOfCoalInReserve += amountMined;
}
}
This would create a function for a Workshop class that would add an amount of coal to the reserves. You could then use that method with any Workshop variable.
NorthAmericaWorkshop.MineCoal(200);
Easy, right?
New Syntax
With C# 14, there’s a new syntax available to you called “extension members” that can make it a bit more clear in your code. You still create a static class to put your extensions in to, but now there’s a new syntax you can use to group related extensions into a logical grouping called “extension blocks”. The docs define extension blocks as:
A block in a non-nested, nongeneric, static class that contains extension members for a type or an instance of that type.
You’ll get a better idea by looking at the following example:
public static class ExtensionClass
{
extension(Workshop workshop)
{
public void AddToNiceList(Kid kid)
{
workshop.NiceList.Add(kid);
}
public void AddToNaughtyList(Kid kid)
{
workshop.NaughtyList.Add(kid);
}
public void MineCoal(int amount)
{
workshop.LumpsOfCoalInReserve += amount;
}
}
}
Here you see 3 extension methods created for the Workshop class. It does the same job as the previous syntax, but it’s cleaner, more organized, and more readable than the older syntax with its “static” and “this” on every line approach. You only need a single reference to the receiver object at the top that all the methods can reference, so you don’t need to add the this keyword on every method anymore.
Usage in the rest of your code remains unchanged.
NorthAmericaWorkshop.MineCoal(200);
You can also invoke them like any other static class method.
ExtensionClass.MineCoal(NorthAmericaWorkshop, 200);
Important note: Remember that defined methods in a class or interface take precedence over extension methods for a type or class. So, if you have a class that defines a method called MineCoal and an extension method for that class called MineCoal, the extension method will never get called. It will always call the method defined in the class or its interface. So watch your naming.
Important note #2: Remember that structs are passed by value, not by reference. So, if your extension method modifies values within the struct, you need to make sure that the extension method utilizies the ref keyword.
extension(ref int input){
public void Increment() => input++;
}
Good to know, right?
Extension Properties and Operators
Another thing this new syntax allows you to do is to declare extension properties and operators in addition to extension methods. This was something that you couldn’t do before, and it just adds to usefulness of the new format. How about a property that tells me how many total kids are being covered by that particular workshop? Easy.
public static class ExtensionClass
{
extension(Workshop workshop)
{
public int TotalKids() => workshop.NiceList.Count + workshop.NaughtyList.Count;
}
}
Uh, oh! Donny just got a notification in Discord. Santa has announced that they are merging several groups of workshops together to promote “SYNERGY”! Donny hates corporate buzzwords. But thanks to the new extension method support for operators, he can quickly write an extension that will make it easy and clean to merge the data from multiple workshops into a single workshop.
public static class ExtensionClass
{
extension(Workshop) {
public static Workshop operator + (Workshop left, Workshop right)
{
return new Workshop
{
NiceList = new List<Kid>(left.NiceList).Concat(right.NiceList).ToList(),
NaughtyList = new List<Kid>(left.NaughtyList).Concat(right.NaughtyList).ToList(),
PresentsMade = left.PresentsMade + right.PresentsMade,
PresentsPerNiceKid = Math.Max(left.PresentsPerNiceKid, right.PresentsPerNiceKid),
LumpsOfCoalInReserve = left.LumpsOfCoalInReserve + right.LumpsOfCoalInReserve
};
}
}
}
Note that the syntax for an operator is slightly different. An extension operator needs to be declared with the static keyword. But now that he’s written the extension method, getting a new workshop object to represent the merger in code is as simple as:
var EuroMuricaWorkshop = NorthAmericaWorkshop + EuropeWorkshop;
Now he can easily merge all that data for the reporting purposes without having to redo all his back end data. For now, anyway. No time for that during the holiday rush. He’ll add a task to the backlog to circle back to that massive undertaking later. And we all know what that means!!!
Conclusion
The old syntax is still supported 100%. This isn’t a breaking change and you don’t have to rewrite any of your existing code. But the new syntax in C# 14 for extension members, as well as the addition of extension properties and operators, can make your code much more easily readable and cleaner. And we all like clean code, don’t we? Future you, and the next dev up, (and Donny) will thank you!
