C# 15 & .NET 11: Real Code Examples Every .NET Developer Should See

Views: 13
Comments: 0
Like/Unlike: 0
Posted On: 02-May-2026 23:15 

Share:   fb twitter linkedin
Rahul M...
5034 Points
35 Posts




As .NET continues to evolve, .NET 11 and C# 15 introduce some of the most impactful changes in recent years—especially around type safety, performance, and developer productivity.

If you're a .NET developer working with APIs, microservices, or enterprise apps, this post breaks down real-world code examples you can actually use—not just theory.



1. Union Types (Discriminated Unions) — Finally in C#

This is easily the biggest feature in C# 15.

The Old Way (C# ≤ 14)

Most developers used something like:

 
public class Result
{
    public bool IsSuccess { get; set; }
    public string? Error { get; set; }
    public object? Data { get; set; }
}
Pro
blems:
  • No type safety
  • Runtime casting issues
  • Hard to maintain



C# 15 — Union Types

 
 
union Result<T> = Success<T> | NotFound | ValidationError;

record Success<T>(T Data);
record NotFound(string Message);
record ValidationError(string Error);
 

Real API Usage

 
Result<User> GetUser(int id)
{
    var user = db.Users.Find(id);

    if (user == null)
        return new NotFound("User not found");

    return new Success<User>(user);
}
 

Clean Pattern Matching

var result = GetUser(1);

var response = result switch
{
    Success<User> s => Ok(s.Data),
    NotFound n => NotFound(n.Message),
    ValidationError v => BadRequest(v.Error)
};
👉 This replaces:
  • OneOf
  • Custom wrappers
  • Exception-based flow



2. Advanced Pattern Matching

C# 15 enhances pattern matching to work beautifully with unions.

 
string Handle(Result<int> result) => result switch
{
    Success<int> { Data: > 100 } => "High value",
    Success<int> { Data: <= 100 } => "Normal value",
    NotFound => "Missing",
    ValidationError v when v.Error.Contains("critical") => "Critical error",
    _ => "Unknown"
};
 

👉 Cleaner, safer, and more expressive than nested if-else.



3. Collection Expressions (Cleaner Data Initialization)

Before:

 
var numbers = new List<int> { 1, 2, 3 };
 

C# 15:

 
int[] arr = [1, 2, 3, 4];
List<int> list = [1, 2, 3];
Span<int> span = [1, 2, 3];
 


Spread Operator

 
var moreNumbers = [..arr, 5, 6];
 

👉 Works across arrays, lists, and spans—very flexible.



4. Interceptors (AOP-like Power)

Interceptors allow compile-time method interception.

 
[InterceptsLocation("Program.cs", line: 10, column: 5)]
public static void LogInterceptor()
{
    Console.WriteLine("Method intercepted!");
}
 

Use Cases:

  • Logging
  • Validation
  • Caching
  • Metrics

⚠️ Still evolving, but powerful for frameworks and libraries.



5. Primary Constructors Everywhere

Less boilerplate for dependency injection.

Before:

 
public class OrderService
{
    private readonly IRepo _repo;

    public OrderService(IRepo repo)
    {
        _repo = repo;
    }
}
 

C# 15:

 
public class OrderService(IRepo repo)
{
    public Order Get(int id) => repo.Get(id);
}
 

👉 Cleaner and more maintainable.



6. Async Improvements (Under the Hood)

No syntax change, but major runtime improvements:

 
public async Task<string> GetDataAsync()
{
    await Task.Delay(100);
    return "Done";
}
 

What improves:

  • Better performance
  • Reduced allocations
  • Cleaner stack traces


7. Real ASP.NET Core Example

Putting it all together:

 
union ApiResult<T> = Ok<T> | NotFound | Error;

record Ok<T>(T Data);
record NotFound(string Message);
record Error(string Message);

app.MapGet("/users/{id}", (int id) =>
{
    ApiResult<User> result = GetUser(id);

    return result switch
    {
        Ok<User> u => Results.Ok(u.Data),
        NotFound n => Results.NotFound(n.Message),
        Error e => Results.BadRequest(e.Message)
    };
});
 

👉 This is clean, type-safe, and production-ready (once stable).



Why This Matters

Biggest Wins in C# 15:

  • Type-safe APIs with Union Types
  • Cleaner logic with Pattern Matching
  • Less boilerplate with Primary Constructors
  • Better performance with runtime async improvements



Should You Use It Today?

 Use C# 15 / .NET 11 if:

  • You're experimenting
  • Building internal tools
  • Exploring modern patterns

 Avoid if:

  • You're building production systems
  • You need long-term stability

👉 For production, stick to .NET 10 (LTS) for now.



Final Thoughts

C# 15 isn’t just an incremental update—it’s a shift toward safer, more expressive code.

The introduction of Union Types alone will change how .NET developers design APIs and handle errors.

 


 

0 Comments
 Log In to Chat