.NET 10 Extension

Apr 15 2025

🚀 Coming Soon: Enforcing Code Style

 

A brand-new course is launching soon inside The CodeMan Community!

 

Join now to lock in early access when it drops - plus get everything else already inside the group.

 

Founding Member Offer:
• First 100 members get in for just $4/month - 70 spots already taken!
• Or subscribe for 3 months ($12) or annually ($40) to unlock full access when the course goes live.

 

Get ahead of the game - and make clean, consistent code your superpower.

 

Join here

 
 

New "extension" keyword in .NET 10

 
 

With .NET 10 extension feature now you can define extension blocks for any type. It is shaping up to be one of the most exciting updates in recent years - and one of the most underrated gems is the new extension keyword introduced in C# 14 (Preview 3).

 

If you thought extension methods were powerful before, this takes things to a whole new level.

 

In this article, I’ll break down:
• What the new extension feature does
• Why it matters
• Real-world use cases you couldn’t solve cleanly before
• And how it changes the way we organize logic around existing types

 
 

Wait, what’s wrong with Extension Methods?

 
 

With the new syntax, you can define extension blocks for any type.
These blocks allow:

 

• Extension properties
• Private backing fields inside the extension scope
• Grouped logic in a clean and local context

 

Syntax:

public static class MyExtensions
{
    extension(TargetType instance)
    {
        public ReturnType PropertyOrMethod => ...;
    }

    extension static
    {
        public static ReturnType StaticHelper() => ...;
    }
}

 
 

Real-World Use Case: Multi-Tenant SaaS and HttpContext

 
 

Let’s say you’re building a multi-tenant SaaS product. You need to:

 

• Extract the TenantId from claims
• Parse and validate the UserId
• Check if the user is a tenant admin
• Read custom headers
• Expose defaults and validation logic

 

The old way? You’d create scattered static methods.
The new way? One structured block with everything grouped and cached.

public static class MultiTenantHttpContextExtensions
{
    extension(HttpContext ctx)
    {
        private string? _tenantId;
        private Guid? _userId;

        public string TenantId =>
            _tenantId ??=
                ctx.User.Claims.FirstOrDefault(c => c.Type == "tenant_id")?.Value
                ?? throw new UnauthorizedAccessException("Tenant ID missing");

        public Guid UserId =>
            _userId ??=
                Guid.TryParse(
                    ctx.User.Claims.FirstOrDefault(c => c.Type == "user_id")?.Value, out var id)
                ? id
                : throw new UnauthorizedAccessException("User ID invalid");

        public bool IsTenantAdmin =>
            ctx.User.IsInRole("Admin") || ctx.Request.Headers["X-Tenant-Admin"] == "true";

        public string? GetHeader(string name) =>
            ctx.Request.Headers.TryGetValue(name, out var value)
                ? value.ToString()
                : null;
    }

    extension static
    {
        public static string DefaultTenantId => "public";

        public static bool IsValidTenantId(string? id) =>
            !string.IsNullOrWhiteSpace(id) && id.All(char.IsLetterOrDigit);
    }
}
This approach brings:
• Readable, organized logic
• Lazy caching via private fields (_tenantId, _userId)
• Cohesive domain logic scoped to the right context

 
 

Another Example: Extending External Models

 
 

Let’s say you’re working with a third-party DTO:

public class OrderDto
{
    public List<OrderItemDto> Items { get; set; }
    public string Status { get; set; }
}

 

With new extensions, you can wrap domain logic around it without modifying the class:

public static class OrderExtensions
{
    extension(OrderDto order)
    {
        public decimal TotalAmount =>
            order.Items.Sum(i => i.Quantity * i.PricePerUnit);

        public bool IsComplete =>
            order.Status == "Completed";

        public int TotalItems =>
            order.Items.Sum(i => i.Quantity);
    }
}
Usage becomes clean and expressive:

 


if (order.TotalAmount > 1000 && order.IsComplete)
{
    // Do something
}

 
 

Why not just use methods from .NET 10?

 
 

Comparing with Extension Methods

This isn't just a cosmetic change - it's a paradigm shift in how we organize logic.

 
 

My Gotchas & Notes

 
 

• This is currently available in .NET 10 Preview 3 with C# 14
• Still being refined, so expect updates in syntax and tooling support
• All your existing extension methods continue to work - this is purely additive

 
 

My Advice

 
 

Use this when you’re extending a type with multiple behaviors that feel like they belong together:

 

• DTO transformations
• HTTP context and claims logic
• Computed values on external models
• Domain-specific enhancements (e.g., IsActive, TotalAmount, NeedsSync, etc.)

 

It keeps your logic close, clean, and cache-friendly - and once you start using it, you won’t want to go back.

 
 

Wrapping Up

 
 

The new extension keyword isn’t flashy at first glance. But it solves a real pain point for developers who care about clean architecture, rich domain modeling, and maintainable code.
It gives us the power we didn’t even know we were missing in C# - and it’s just the beginning of a new era of expressiveness.

 

Let me know if you'd like to see how I plan to use this in:

 

• CQRS helpers
• ViewModel builders
• ASP.NET Core service pipelines

 

Because I already note what I can refactor for some of my older projects.

 

That's all from me today.

 

P.S. Follow me on YouTube.

There are 3 ways I can help you:

My Design Patterns Ebooks

1. Design Patterns that Deliver

This isn’t just another design patterns book. Dive into real-world examples and practical solutions to real problems in real applications.Check out it here.


1. Design Patterns Simplified

Go-to resource for understanding the core concepts of design patterns without the overwhelming complexity. In this concise and affordable ebook, I've distilled the essence of design patterns into an easy-to-digest format. It is a Beginner level. Check out it here.


Join TheCodeMan.net Newsletter

Every Monday morning, I share 1 actionable tip on C#, .NET & Arcitecture topic, that you can use right away.


Sponsorship

Promote yourself to 15,250+ subscribers by sponsoring this newsletter.



Join 15,250+ subscribers to improve your .NET Knowledge.

Powered by EmailOctopus

Subscribe to
TheCodeMan.net

Subscribe to the TheCodeMan.net and be among the 15,250+ subscribers gaining practical tips and resources to enhance your .NET expertise.

Powered by EmailOctopus