We introduced a new attribute, System.Runtime.CompilerServices.OverloadResolutionPriority
, that can be used by API authors to adjust the relative priority of
overloads within a single type as a means of steering API consumers to use specific APIs, even if those APIs would normally be considered ambiguous or otherwise
not be chosen by overload resolution rules. See Overload Resolution Priority in C#.
API authors often run into an issue of what to do with a member after it has been obsoleted. For backwards compatibility purposes, many will keep the existing member around
with ObsoleteAttribute
set to error in perpetuity, in order to avoid breaking consumers who upgrade binaries at runtime. This particularly hits plugin systems, where the
author of a plugin does not control the environment in which the plugin runs. The creator of the environment may want to keep an older method present, but block access to it
for any newly developed code. However, ObsoleteAttribute
by itself is not enough. The type or member is still visible in overload resolution, and may cause unwanted overload
resolution failures when there is a perfectly good alternative, but that alternative is either ambiguous with the obsoleted member, or the presence of the obsoleted member causes
overload resolution to end early without ever considering the good member. For this purpose, we want to have a way for API authors to guide overload resolution on resolving the
ambiguity, so that they can evolve their API surface areas and steer users towards performant APIs without having to compromise the user experience.
We define a new concept, overload_resolution_priority, which is used during the process of overload resolution. overload_resolution_priority is a 32-bit integer
value. All methods have an overload_resolution_priority of 0 by default, and this can be changed by applying
OverloadResolutionPriorityAttribute
to a method. We update section
Overloaded Method Resolution of the VB specification as
follows (change in bold):
- Next, eliminate all members from the set that are inaccessible or not applicable (Section Applicability To Argument List) to the argument list
3. Then, the reduced set of candidate members is grouped by declaring type. If the member is an override, the declaring type and the overload_resolution_priority come from the least-derived declaration of that member. Within each group:
- A maximum overload_resolution_priority among candidates that do not utilize narrowing conversions or narrowing delegate relaxation is determined.
- All members that have a lower overload_resolution_priority than the maximum found during the previous step, if any, within its declaring type group are removed.
The reduced groups are then recombined into the set of candidates.
4. Next, if one or more arguments are
AddressOf
or lambda expressions, then calculate the delegate relaxation levels for each such argument as below. If the worst (lowest) delegate relaxation level inN
is worse than the lowest delegate relaxation level inM
, then eliminateN
from the set. The delegate relaxation levels are as follows:
As an example, this feature would cause the following code snippet to print "I1", rather than failing compilation due to an ambiguity:
Public Interface I1
End Interface
Public Interface I2
End Interface
Public Interface I3
Inherits I1, I2
End Interface
Public Class C
<OverloadResolutionPriority(1)>
Public Shared Sub M(x As I1)
System.Console.WriteLine("I1")
End Sub
Public Shared Sub M(x As I2)
System.Console.WriteLine("I2")
End Sub
End Class
Public Class Program
Shared Sub Main()
Dim i3 As I3 = Nothing
C.M(i3)
End Sub
End Class
Negative numbers are allowed to be used, and can be used to mark a specific overload as worse than all other default overloads.
The overload_resolution_priority of a member comes from the least-derived declaration of that member. overload_resolution_priority is not
inherited or inferred from any interface members a type member may implement, and given a member Mx
that implements an interface member Mi
, no
warning is issued if Mx
and Mi
have different overload_resolution_priorities.
There is the following attribute in the BCL:
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public sealed class OverloadResolutionPriorityAttribute(int priority) : Attribute
{
public int Priority => priority;
}
All methods in VB have a default overload_resolution_priority of 0, unless they are attributed with OverloadResolutionPriorityAttribute
. If they are
attributed with that attribute, then their overload_resolution_priority is the integer value provided to the first argument of the attribute.
Overload Resolution process does not perform filtering by overload_resolution_priority in VB < 17.13. No errors or warnings issued by the Overload Resolution process due to the fact that overload_resolution_priority was ignored in this case.
By analogy with C# we could make it an error to apply OverloadResolutionPriorityAttribute
to the following locations:
- Property, or event accessors
- Conversion operators
- Finalizers
- Shared constructors
- Overriding properties
- Overriding methods
Attributes encountered on these locations in metadata effectively will have no impact in VB code.
Reporting an error might be a breaking change because VB allowed the attribute at any location before.
Should a langversion errors be issued when OverloadResolutionPriorityAttribute
is applied?
Reporting the error might be a breaking change because VB allowed the attribute in the previous version.