C# 14 Extension Members: Enhancing Polyfill Libraries

 
 
  • Gérald Barré

C# has long supported extension methods, allowing developers to add new methods to existing types without modifying the original type. However, this capability was limited to instance methods. With C# 14, the language introduces extension members, significantly expanding what you can extend. You can now add extension properties and extension static methods to existing types. This enhancement is particularly valuable for polyfill libraries, which aim to backport newer APIs to older .NET versions.

#Why Extension Members Matter for Polyfill Libraries

Polyfill libraries help developers write code that uses modern APIs while targeting multiple .NET versions. As I explained in my previous post about polyfills, these libraries provide implementations of newer APIs for older target frameworks, reducing the need for #if directives in your code.

Before C# 14, polyfill libraries could only provide instance methods through extension methods. This limitation meant that static methods and properties from newer .NET versions couldn't be polyfilled effectively. C# 14 removes this restriction, allowing polyfill libraries to provide a more complete experience.

You can read more about extension members in my previous post Use C# 14 extensions to simplify enum Parsing or in the introduction post C# 14 – Exploring extension members.

#Real-World Example: ArgumentNullException.ThrowIfNull

A perfect example is the ArgumentNullException.ThrowIfNull static method, introduced in .NET 6. This method provides a concise way to validate that a parameter is not null:

C#
public void ProcessData(string data)
{
    ArgumentNullException.ThrowIfNull(data);

    // Process the data...
}

Prior to C# 14, polyfill libraries couldn't provide ThrowIfNull as a static method on ArgumentNullException because extension methods only worked for instance methods. With C# 14's extension static methods, polyfill libraries can now provide this exact API, even when targeting older .NET versions. Now you can write code that uses ArgumentNullException.ThrowIfNull regardless of your target framework, improving code readability and maintainability.

C#
static class PolyfillExtensions
{
    extension(ArgumentNullException)
    {
        public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
        {
            if (argument is null)
                throw new ArgumentNullException(paramName);
        }
    }
}

While you can define your own extension static methods and properties, using a well-maintained polyfill library can save you time and effort.

#Using Meziantou.Polyfill with Extension Members

The Meziantou.Polyfill package (GitHub) can polyfill more than 350 types, methods and properties. It leverages C# 14's extension members to provide a comprehensive polyfilling experience. The package uses source generators to automatically add only the polyfills you need based on your target framework.

To install the package:

Shell
dotnet add package Meziantou.Polyfill

Once installed, you can use modern .NET APIs like ArgumentNullException.ThrowIfNull even when targeting older frameworks such as .NET Standard 2.0 or .NET Framework:

C#
public class UserService
{
    public void CreateUser(string username, string email)
    {
        // Works on .NET Standard 2.0 and later thanks to extension static methods
        ArgumentNullException.ThrowIfNull(username);
        ArgumentNullException.ThrowIfNull(email);

        // Create user logic...
    }
}

The source generator automatically detects your target framework, C# version, and compilation options to generates the appropriate extension members only when needed and possible. So, if you are not using C# 14 or later, or if the target framework already includes the API, no polyfill is generated.

#Conclusion

C# 14's extension members represent a significant evolution in the language's extensibility model. By allowing extension properties and static methods, the feature enables polyfill libraries to provide a more complete and seamless experience when targeting multiple .NET versions. This means less #if directives, more maintainable code, and the ability to use modern APIs even when supporting older frameworks.

Whether you're using a polyfill library like Meziantou.Polyfill or creating your own extension members, this feature opens up new possibilities for writing cleaner, more expressive code that works across multiple .NET versions.

#Additional Resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub