With the latest preview: .NET 10 preview 3, we did get an overhaul on extensions. It might enable some nice tricks in the future.
Extensions#
The new feature called Extension members is basically extending the already existing extensions and bringing them to the next level.
If we had this in the pre-C# 14 world:
public static class Extensions
{
public static IEnumerable<int> WhereGreaterThan(this IEnumerable<int> source, int threshold)
=> source.Where(x => x > threshold);
}
We can achieve the same with this new syntax:
public static class Extensions
{
extension(IEnumerable<int> source)
{
public IEnumerable<int> WhereGreaterThan(int threshold)
=> source.Where(x => x > threshold);
public bool IsEmpty
=> !source.Any();
}
}
As you can see, we can group similiar things easier together. Until now, this is basically a new syntax but we didn't achieve anything new. But that changes:
Extending with static methods#
The new cool thing is that you can new static methods on top of a type:
extension<T>(List<T>)
{
public static List<T> Create()
=> [];
}
Now, you can call:
var foo = List<int>.Create();
Okay, so far, so good. But what can we do with that? Well there are two cool features that might be possible (they are not right now).
Adding static operators to 3rd party types#
We can easily add operators to existing 3rd party types. They are defined as static invocations on a type, so we can do something like this:
public class MyObject(int number)
{
public int Number { get; } = number;
}
public static class Extensions
{
extension(MyObject)
{
public static int operator +(MyObject x, MyObject y)
{
return x.Number + y.Number;
}
}
}
Remember MyObject itself doesn't define any + but the extension does. So we would be allowed to do something like:
var m1 = new MyObject(2);
var m2 = new MyObject(3);
Console.WriteLine(m1 + m2);
Adding new collection expressions on unsupported types#
Basically, what we want is to allow the [1,2,3] syntax for types that currently don't support that. I took as an example IReadOnlySet<T>. If you are not aware what collection expressions are or how to build them for your own types: https://andrewlock.net/behind-the-scenes-of-collection-expressions-part-5-adding-support-for-collection-expressions-to-your-own-types/
So, while currently not working, we might have a chance that we can equip 3rd party types as such:
IReadOnlySet<int> set = [1, 2, 3];
[CollectionBuilder(typeof(Extensions), nameof(Extensions.Create))]
public static class Extensions
{
extension<T>(IReadOnlySet<T>)
{
public IReadOnlySet<T> Create(ReadOnlySpan<T> items)
{
return new HashSet<T>(); // Here something useful
}
}
}
The problem is that the compiler doesn't look on any other type than the target type for the attribute - so while the extension does compile, it does not create the effect I was aiming for. Let's see in the future which cool things we can enable with this new language feature.