Extension methods have been around in C# for a long time. They allow you to add new methods to existing types without modifying their source code. This is very useful when working with types from frameworks or libraries you do not own.
However, extension methods have one annoyance: every method must be defined in a static class, and each method must declare the first parameter with the this modifier. When you write several extension methods for the same type, your code starts to feel repetitive.
Extension Members, were introduced to solve this problem by allowing you to group extension methods inside an extension block tied to a specific type.
What Are Extension Members?
Extension members let you define an extension scope like this:
extension System.String
{
// instance extension
int WordCount() => this.Split(' ').Length;
// static extension
static bool IsNullOrEmpty(string? value) => string.IsNullOrEmpty(value);
}
Before vs After
Before(Classic Extension Methods)
public static class StringExtensions
{
public static int WordCount(this string text)
{
return text.Split(' ').Length;
}
}
After(Extension Block)
extension System.String
{
int WordCount() => this.Split(' ').Length;
}
Example
extension System.String
{
bool IsLong() => this.Length > 20;
static string? EmptyIfNull(string? value) => value ?? string.Empty;
}
Usage
string message = "Hello World";
bool isLong = message.IsLong();
string result = string.EmptyIfNull(null);
Extension Members Priority Rule
Extension members are always lower priority than the type's existing members. Meaning: if the type already defines a method with the same name, the type's method is used.
Example
extension System.String
{
string ToUpper() => "Extension ToUpper called";
}
var text = "hello";
Console.WriteLine(text.ToUpper());
Output
HELLO
=> The built-in string.ToUpper() wins.
Extension Members in C# 14 – What Changed?
C# 13 introduced the extension block, which allows you to define methods and static helpers on existing types more naturally. C# 14 takes this further by allowing you to define more kinds of members, not just methods.
Example: Extension Property (C# 14)
extension System.String
{
int WordCount => this.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
}
Usage
string text = "Hello world from C#";
Console.WriteLine(text.WordCount); // 4
No parentheses. It behaves exactly like a read-only property.
Example: Extension Indexer (C# 14)
extension System.String
{
char this[Index index] => this[index];
}
Usage
string s = "Hello";
Console.WriteLine(s[^1]); // o
This allows idiomatic slicing without writing your own helper code.
Top comments (0)