C# 13 new feature: Extension types

One of the features demonstrated by Mads Torgersen and Dustin Campbell in the "What’s new in C#" talk at Microsoft Build 2024 that I really like is the introduction of extension types.

Extension methods have been allowed since C# 3 and are widely used by .NET developers. Their main objective is to allow developers to add methods to a type. It's useful if you don't want to modify the type or, in most cases of extension usage, if you don't have access to the underlying code. LINQ is an example of a set of extension methods on IEnumerable.

Although extension methods are very useful and widely used, they have some limitations. First, you can only add methods, you cannot add properties or any members other than methods. Secondly, all extension methods have to be static. C# 13 introduces a new version of extension methods called Extension types that takes the next step. With extension types you can add methods to a type, but also any other member. The members you add can be static but also instance members, even if instance extension types cannot hold state. Finally, extension types can be implicit (they will apply to all occurrences of the underlying type) or explicit (you will have to explicitly convert the underlying type to the extension type you want to use).

Let's see what it looks like.

Assume we are using this code, which we can't change:


  public enum MusicInstrumentsEnum
{
    Guitar = 1,
    BassGuitar = 2,
    Drum = 3
}

public class Musician()
{
    public required string FirstName { get; init; } 
    public required string LastName { get; init; }
    public required Band Band { get; init; } 
    public MusicInstrumentsEnum? Instrument { get; init; }
    public required bool IsSinger { get; init; } 
}

// It's pretty reductive about music but it's just for the example!
public class Band()
{
    public required string Name { get; init; }
    public required IEnumerable Musicians { get; init; } 
    public required IEnumerable Albums { get; init; }
}

public class Song()
{
    public required string Name { get; init; }
    public required bool ReleasedOnRadio { get; init; }
}

public class Album
{
    public required string Name { get; init; }
    public required IEnumerable Songs { get; init; }
    public required int SalesCount { get; init; }
}

Imagine you want to know if a musician has played on an album that is a Gold Record; with extension types you can do it this way:


public implicit extension MusicianExtension for Musician
{
    public bool HasPlayedOnGlodRecordAlbum
        => this.Band
            .Albums
            .Any(album => album.SalesCount >= 500_000);
}

This property would be called like this:


if(musician.HasPlayedOnGlodRecordAlbum)
{
   // ...
}

With explicit extensions you can implement other features, like retrieving the list of the Gold Record albums a musician played on:


public explicit extension GlodRecordMusician for Person
{
    public IEnumerable GoldRecords 
        => this.Band
            .Albums
            .Where(album => album.SalesCount >= 500_000);
}

This property would be called like this:


if (musician.HasPlayedOnGlodRecordAlbum)
{
    GlodRecordMusician glodRecordMusician = musician;
    IEnumerable albums = glodRecordMusician.GoldRecords;
}

Extension types do not replace the extension methods introduced in C# 3; they are an add-on, a new tool you can use to simplify your code or organize it better.

For more information about it or about other new C# features, watch the "What’s new in C#" talk.

May 31, 2024
  • C#
  • Csharp
  • C# 13
  • Expression types