Adding static getter thanks to extensions

7/19/2026
2 minute read

Here a simple scenario: You have a StringComparer and you want to add your own comparer to the mix - for example a "natural sort" order, so "file2" sorts before "file10" instead of after.

With C# 14 we can extend the family and make it feel natural!

A new comparer

So we want to add and use something like:

public class NaturalSortComparer : StringComparer
{
    public override int Compare(string? x, string? y) => ...
    public override bool Equals(string? x, string? y) => ...
    public override int GetHashCode(string obj) => ...
}

Pre C# 14

Before C# 14, "extending" a type meant extension methods - so we can only do things like:

public static class StringComparerExtensions
{
    public static StringComparer NaturalSort(this StringComparer comparer) => new NaturalSortComparer();
}

Which then feels odd to use: StringComparer.Ordinal.NaturalSort();. Hmm not great. If we have a look at the other folks in the family: StringComparer.OrdinalIgnoreCase and so on, we are far away!

Alternatively, we could do is a separate class:

public static class NaturalSort
{
    public static StringComparer Instance { get; } = new NaturalSortComparer();
}

// Usage:
var files = Directory.GetFiles(path)
                      .OrderBy(f => f, NaturalSort.Instance);

C# 14

C# 14 extension blocks can add static members too, not just methods but properties

public static class StringComparerExtensions
{
    extension(StringComparer)
    {
        public static StringComparer NaturalSort => new NaturalSortComparer();
    }
}

With this we can now use it as we want to (as in: As I want to!):

var files = Directory.GetFiles(path)
                      .OrderBy(f => f, StringComparer.NaturalSort);

Amazing! Steven over and out.

An error has occurred. This application may no longer respond until reloaded.Reload x