SHARE:

C# 14: Introducing Extension Members

Introduction

C# continues to evolve with every major release, and C# 14 is no exception.
This time, the language introduces a feature that many developers have been wishing for over the years: extension members.

Until now, C# only allowed extension methods. They were convenient, but also limited. With C# 14, we can finally extend types with properties, methods, and even static members, all grouped under a dedicated extension block.

In this post, we’ll explore how this works, why it matters, and what it means for designing richer, more expressive APIs.

Before C# 14: Extension Methods Only

Before C# 14, if you wanted to extend a type you didn’t own, you had one tool: the extension method. Example:

public static class StringExtensions
{
    public static bool IsLong(this string value)
        => value.Length > 50;
}

Nice and familiar. You call it as:

This works, but:

  • You cannot add properties
  • You cannot add static members
  • You cannot group extensions by receiver type
  • You must repeat the receiver type for every method

The concept was powerful, but not flexible.

What’s new in C# 14?

C# 14 introduces a new syntax:

extension(TypeName receiver) 
{
    // extension members go here
}

Inside this block, you can define:

  • Instance extension properties
  • Instance extension methods
  • Static extension properties
  • Static extension methods

This means you can now give external types a much more complete “virtual surface” of functionality — without modifying the original code, and without inheriting from it.

A Completely Original, Real-World Example

A common scenario in modern applications is working with sensor readings, telemetry, or IoT data.
Let’s build an example around a minimal domain type: TemperatureReading

Domain type:

public sealed class TemperatureReading(double value, DateTime timestamp)
{
    public double Value { get; } = value;
    public DateTime Timestamp { get; } = timestamp;
}

Now let’s extend it with C# 14’s new extension syntax.

Extension members:

public static class TemperatureReadingExtensions
{
    // Instance extension members
    extension(TemperatureReading r)
    {
        // Converts Celsius to Fahrenheit
        public double Fahrenheit => (r.Value * 9d / 5d) + 32d;

        // Checks whether the value exceeds a threshold
        public bool IsCritical(double threshold = 35)
            => r.Value >= threshold;

        // Human-friendly representation
        public string ToLabel()
            => $"{r.Value:0.0} °C at {r.Timestamp:HH:mm:ss}";
    }

    // Static extension members
    extension(TemperatureReading)
    {
        // Create a reading from °F inputs
        public static TemperatureReading FromFahrenheit(double f, DateTime timestamp)
            => new((f - 32d) * 5d / 9d, timestamp);

        // Neutral reading used for testing or diagnostics
        public static TemperatureReading Neutral
            => new(0, DateTime.UnixEpoch);
    }
}

Usage:

var reading = new TemperatureReading(29.4, DateTime.UtcNow);

double f = reading.Fahrenheit;          // instance property
bool alert = reading.IsCritical(30);    // instance method
string label = reading.ToLabel();       // method with formatting

var converted = TemperatureReading.FromFahrenheit(100, DateTime.UtcNow); // static extension
var baseline = TemperatureReading.Neutral;                               // static property

Why Extension Members Matter

1. More expressive APIs

1. More expressive APIs

Some behaviors are better expressed as properties than methods:

  • IsEmpty
  • IsCritical
  • IsValid
  • IsExpired

Before C# 14, extension properties were impossible.

2. Better type modeling without modifying the original code

A domain model from another team or library can now be extended elegantly:

  • Add formatting helpers
  • Add calculations
  • Add computed values
  • Add static factories

All without modifying the original type.

3. Cleaner grouping of extensions

Instead of repeating:

public static class XExtensions
{
    public static ...
    public static ...
    public static ...
}

You can logically group by receiver type:

extension(MyType)
{
    ...
}

This keeps your extension library readable and maintainable.

Conclusion

Extension members in C# 14 greatly expand what developers can do without touching the underlying types. Properties, static members, and a cleaner syntax open the door to more expressive, discoverable, and maintainable APIs.

This feature will be particularly appreciated by:

  • Library authors
  • Domain-driven design practitioners
  • Teams that work with immutable or external models
  • Anyone building clean, expressive codebases

C# 14 is a small but meaningful step forward — and extension members are one of the features that will quietly improve day-to-day development for many of us.

Written by

anthonygiretti

Anthony is a specialist in Web technologies (14 years of experience), in particular Microsoft .NET and learns the Cloud Azure platform. He has received twice the Microsoft MVP award and he is also certified Microsoft MCSD and Azure Fundamentals.