Description
Background and motivation
In order to support the C# proposed feature https://github.com/dotnet/csharplang/blob/d5bab90e846f9b3e9a7a4e552249643148f0194d/proposals/overload-resolution-priority.md, we add a new attribute to the BCL: OverloadResolutionPriorityAttribute
. This feature allows applying the attribute to adjust the priority of an overload within a type. This will allow consumers like the rest of the BCL to adjust overload resolution for scenarios where a new, better API should be preferred (but won't be because overload resolution would prefer the existing one), or to resolve scenarios that will otherwise be ambiguous. One prime example is Debug.Assert
; with this API, we could adjust void Debug.Assert(bool condition, string? message)
to instead be [OverloadResolutionPriority(1)] Debug.Assert(bool condition, [CallerArgumentExpression(nameof(condition))] string? message = "")
. The real change here would be a bit more complex due to the number of overloads that Debug.Assert
already has, but this is a simple enough example to convey they intent.
API Proposal
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public sealed class OverloadResolutionPriorityAttribute(int priority)
{
public int Priority => priority;
}
API Usage
using System.Runtime.CompilerServices;
var d = new C1();
int[] arr = [1, 2, 3];
d.M(arr); // Prints "Span"
class C1
{
[OverloadResolutionPriority(1)]
public void M(ReadOnlySpan<int> s) => Console.WriteLine("Span");
// Default overload resolution priority
public void M(int[] a) => Console.WriteLine("Array");
}
Alternative Designs
No response
Risks
One of the BCL's main uses of OverloadResolutionPriorityAttribute
will be to effectively make source-breaking changes while maintaining binary compatibility. Care will have to be taken when using the attribute to ensure only the intended consequences occur. For a few of these cases, it can effectively make specific overloads impossible to call directly, and users would have to resort to using something like delegate conversion, UnsafeAccessor
, reflection, or manual IL.