meetings/2025/LDM-2025-04-16.md
Champion issue: https://github.com/dotnet/csharplang/issues/8697
Specification: https://github.com/dotnet/csharplang/blob/feb7a075739e81393def6c28ab12eb7b8fdc3bb6/proposals/extensions.md#open-issues
Nullability attributes there are some scenarios where the attributes can be placed on the receiver parameter but may feel odd or be inappropriate. For example, if an attribute refers to a method parameter name, like NotNullIfNull, nameof cannot be used. The name of the parameter has to be used.
These attributes can be placed on extension methods with the traditional syntax.
If the attribute includes a name, and the name does not exist on one of the extension methods in the block, it will be ignored. This is consistent with existing behavior for nullability attributes.
We will copy these attributes to the lowered version of the extension method, in the same way we copy any other attribute. We will do no special work for these cases. This avoids breaking changes for people moving from the traditional syntax to the new syntax, except in the case where they used nameof on a parameter other than the receiver parameter.
NotSupportedException or null?These methods should not be called, and are marked as special methods. However, NotSupportedException better explains the intent.
NotSupportedException is preferred.
A future version might add more parameters.
This is an implementation detail the team can choose. We do not have scenarios where we would need a second parameter.
This is a discussion of the compiler special name. It's up to the compiler to decide what is appropriate.
The implementation method also are currently marked with special name. This may not be appropriate since the implementation has switched to speakable names.
The extension method will be marked with special name.
The implementations method will not be marked with special name.
Overload resolution priority attribute (ORPA) is meant to differentiate overloads within the same type. For the new extension syntax, what does the notion of the containing type mean?
Using the containing static class, rather than the extension block is compatible with traditional extension methods, and supports the case where extensions with the same receiver parameter appear in different extension blocks. Given:
public static class Extensions
{
extension(Type1)
{
[OverloadResolutionPriority(1)]
public void Overload(...)
}
extension(Type2)
{
public void Overload(...)
}
// same bucket/ same "containing type"
public static void Overload(this Type3, ...)
}
If the containing type is the static Extensions class, all three overloads considered together.
The containing type is the static class. The extension block is not considered.
public static class Extensions
{
extension(PrivateType p)
{
// We report inconsistent accessibility error,
// because we generate a `public static void M(PrivateType p)` implementation in enclosing type
public void M() { }
public static void M2() { } // should we also report here, even though not technically necessary?
}
private class PrivateType { }
}
We don't strictly need the to give an error here, but it is not a helpful since the underlying type is inaccessible.
Providing the error would be consistent with the general behavior of accessing private types within public methods.
Apply the "inconsistent accessibility" check on the receiver parameter.
init accessors are intended for use during object creation and limited to that timeframe.
If we do not do this now, we could do this later. We could consider it in relation to other enhancements to object creation.
We will not allow init accessors on extension properties.
This is a discussion of Extension static member lookup on generic types does not work.
static void Test<T>()
{
T.Hello(); // error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter
}
static class Ext
{
extension<T>(T)
{
public static void Hello()
{
Console.WriteLine("Hello");
}
}
}
You cannot currently call static members on type parameters in non-extension code. A constraint is available and the static method can be called on the constraint.
Calling static extension members with type parameters may be more useful than non-extensions.
Design work would be needed to support this.
This may be a valuable scenario, but we are going to wait for feedback.