When .NET 9 was released we got extension members. I am sure we have only seen the beginning of them, as there is a lot of potential in that (if you ask me). They are a way for developers to improve existing types.
To make it easier to understand what I mean, I have prepared a simple example for you:
// This will be possible in .NET 10
extension StringExtensions for string
{
public int WordCount => this.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
}
// Using it
string sentence = "This is a test";
int count = sentence.WordCount; // 4See the awesome part about this? They will give you a feeling that the extension is at language-level. It's not just a static method you added as a workaround. With the extension members we can easily add new methods or properties to our existing types.
🧑💻 A Practical Example
Let's make a practical example to see how we can utilize this in a real world. I have created a set of classes for your reference.
public abstract class Vehicle
{
public string Make { get; set; }
public string Model { get; set; }
public sealed class Car : Vehicle
{
public int NumberOfDoors { get; set; }
public bool IsElectric { get; set; }
}
public sealed class Truck : Vehicle
{
public double PayloadCapacity { get; set; }
public bool HasFourWheelDrive { get; set; }
}
public sealed class Motorcycle : Vehicle
{
public bool HasSidecar { get; set; }
public string EngineType { get; set; }
}
}
Imagine you would like to perform some sort of validation on the truck for e.g. the payload capacity. That would end up in something similar to this code:
var truck = new Vehicle.Truck();
if (truck is Vehicle.Truck t)
{
if (t.PayloadCapacity <= 0)
{
// Handle invalid payload (e.g., throw, set default, etc.)
}
else
{
// Payload is OK
}
}
This becomes a bit cluttered, what if you could do all of that in an extension using the new extension members being available from .NET 10?
public static class VehicleExtensions
{
extension(Vehicle.Truck truck)
{
public bool HasValidPayload => truck.PayloadCapacity > 0;
}
}
This provides us with an extension for the Truck class now where the validation is abstracted away from the condition we made before. Let's use it to validate the payload.
var truck = new Vehicle.Truck { PayloadCapacity = 5.0 };
if (truck.HasValidPayload)
{
Console.WriteLine("Truck payload capacity is valid.");
}
else
{
Console.WriteLine("Truck payload capacity is invalid!");
}
See how clean my conditional logic became after doing that? It's now fully readable 💪 One thing I really like about this is that we now get the option to extend static classes and that is pretty awesome! 🔥
But it doesn't stop here, there is much more we can do. Below are a few examples to showcase it.
🧱 Extending Enums
Enums can be extended as well. When I first read that I was curious about what was possible. One thin I often see written over and over again are parsers for enums.
Yes... I have done a few myself in various projects, but this can be handled pretty beautiful with an extension.
Suppose you have a VehicleType enum.
public enum VehicleType
{
Car,
Truck,
Motorcycle
}Let's write an extension to parse a string to the enum member.
public static class VehicleTypeExtensions
{
extension<T>(T) where T : struct, Enum
{
public static T Parse(string value) =>
Enum.Parse<T>(value);
}
}And applied in the business logic, it ends up like this.
var type = VehicleType.Parse("Truck");
Console.WriteLine(type); // Output: TruckThat is how easy it is. I know that example is pretty simple, but it is also just to showcase what is possible.
What about null or empty values? Something we hate as developers 😅
🚨 Null and Empty Checks
Image you have a List<string> representing installed parts on a vehicle, and you want to ensure the list isn’t empty. How could we easily accomplish that?
I am so glad you asked... an extension 😆 Let's see how a null/empty check could be implemented using extensions.
public static class VehicleGuardExtensions
{
extension(ArgumentException)
{
public static void ThrowIfPartsListEmpty(IList<string> parts)
{
if (parts.Count == 0)
{
throw new ArgumentException("Vehicle must have at least one part installed.", nameof(parts));
}
}
}
}The extension above will throw an argument exception if the requirement about minimum installed parts are not met. Using it will be as easy as this.
var parts = new List<string>();
ArgumentException.ThrowIfPartsListEmpty(parts);Can you see the idea of doing that? Now we are using the base exception for arguments, but with our own logic behind a saying name making the code super readable for anybody.
I can say that I am already planning to implement this in a lot of the business applications where I got the design responsibility.
Let's have a look at one last thing, and call it.
🔄 Static Extension for Factory Defaults
If you find yourself having default values for a specific kind of your type, e.g. a truck, you could add an extension for creating just that. Let me show you how.
public static class VehicleFactoryExtensions
{
extension(Vehicle)
{
public static Vehicle.Truck CreateDefaultTruck() =>
new Vehicle.Truck
{
Make = "Generic",
Model = "Hauler",
PayloadCapacity = 2.0,
HasFourWheelDrive = true
};
}
}You can see this as a kind of a template, where you define what a default truck is. When applied in business logic, it will look like this.
var defaultTruck = Vehicle.CreateDefaultTruck();
Console.WriteLine(defaultTruck.Model); // Output: Hauler💭 Some Thoughts
I really like the extension members feature! They are a really cool way of making the code clean without having to re-invent the wheel. If you ask me, I think they are more powerfull and expressive at the same time, compared to the traditional extension methods we are building.
My example above was focused on a Vehicle, but it could literally be anything this could be applied to like types (the Vehicle) or static members like enums and factories.
They make our code more readable and when implement in a full codebase, your domain logic will start feeling like it is a natural part of the language. Can it be any better?
Behind all the awesome stuff I just showed and mentioned, there are always some things that could be made better, and hopefully they will in the future, who knows? To mention a few things:
❌ No Fields in Extension Containers
At the moment you cannot define fields inside an extension contianer. Only properties and methods are allowed. That limits a few optimizations or a shared internal state in the extension.
❌ No Private Reuse Across Extension Members
There is no option for reusing private computed properties or logic inside the same extension container. Here is an example:
extension(Vehicle.Truck truck)
{
private bool IsOverloaded => truck.PayloadCapacity > 10;
// ❌ Error: 'IsOverloaded' does not exist in this context
public bool ShouldUpgradeSuspension => IsOverloaded;
}
This is currently not allowed, but would really be a nice feature! It could help improve the readability of the logic and encapsulate the shared logic inside the extension container.
🔐 No Instance Field Access from Extension
Let's say I wanted to give all my vehicles an internal field that only extensions could see. This could be for diagnostics or telemetry (thoughts on top of my head). If the .NET team implemented that, we might get something similar to this:
public abstract class Vehicle
{
internal extension string _diagnosticsId;
}
extension(Vehicle vehicle)
{
private string? DiagnosticsId => vehicle._diagnosticsId;
}
Why would I like that feature? Depends on your project, but I foresee that it could open the option for using patterns to accomplish metaprogramming or do diagnostics at runtime. I am currently building a modular monolith and I really think that this would be great in such a system.
So, what do you think? 😅 How would you use extension members in your codebase? Let me know your thoughts in the comments! Until next time - happy programming! ✌️
📚 References



