Skip to main content

Extend your Extensions in .NET

Starting from .NET 10 we will get new features for extensions. We will now get extension members that will give us the option for extending our extensions 🔥

· By Christian Schou Køster · 7 min read

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;  // 4

See 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.

💡
You can actually define private members (methods or other properties) in the extension container. The only issue (right now) is that private members doesn't serve that much of a purpose at the moment.

🧑‍💻 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: Truck

That 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.

🤓
Metaprogramming is an advanced concept where your code can inspect, modify, or generate other code at runtime or compile time 🔥 don't get scared 😁 I have personally used it for automating stuff. I once build a flexible API that was generated on the fly and even used it for injecting configurations in PLCs dynamically.

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

Metaprogramming - Wikipedia
Extension members - C#
Extension members in C# enable you to add methods, properties, or operators to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.
Extension member declarations - C# reference
Learn the syntax to declare extension members in C#. Extension members enable you to add functionality to types and interfaces in those instances where you don’t have the source for the original type. Extensions are often paired with generic interfaces to implement a common set of functionality across all types that implement that interface.

About the author

Christian Schou Køster Christian Schou Køster
Updated on Nov 24, 2025