-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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.