C# 13 中的 OverloadResolutionPriorityAttribute

C# 13 中的  OverloadResolutionPriorityAttribute

Intro

C# 13 引入了 params collection  的 feature,可以参考我们之前的介绍 C# 13 新特性 params collection,不过有一个问题,我们之前也有提到就是如果我们要针对原来的数组新增 ReadOnlySpan 的重载可能会发生破坏性的变更,原来调用数组方法可能会变成调用 ReadOnlySpan 的方法重载,所以后面引入了 OverloadResolutionPriorityAttribute 来控制方法重载解析的优先级这样开发者可以为原有的方法指定一个较高的优先级来保证不会 break,之前我们也提到过这个 attribute 不过之前编译器还没支持,现在已经支持了

OverloadResolutionPriorityAttribute

Attribute 定义如下:

namespace System.Runtime.CompilerServices
{
    /// <summary>
    /// Specifies the priority of a member in overload resolution. When unspecified, the default priority is 0.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public sealed class OverloadResolutionPriorityAttribute : Attribute
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="OverloadResolutionPriorityAttribute"/> class.
        /// </summary>
        /// <param name="priority">The priority of the attributed member. Higher numbers are prioritized, lower numbers are deprioritized. 0 is the default if no attribute is present.</param>
        public OverloadResolutionPriorityAttribute(int priority)
        {
            Priority = priority;
        }

        /// <summary>
        /// The priority of the member.
        /// </summary>
        public int Priority { get; }
    }
}

默认方法的 priority 是 0priority 越大优先级越高

Sample

来看个使用示例吧,首先我们回顾一下 params collection 里的用法

int[] numbers = [1, 2, 3, 4];
PrintNumbers(numbers);

ReadOnlySpan<int> numbersSpan = numbers.AsSpan();
PrintNumbers(numbersSpan);

PrintNumbers(1, 2, 3);
PrintNumbers([1, 2, 3]);

这里有两个 PrintNumbers 的方法,参数分别是数组和 ReadOnlySpan,定义如下:

private static void PrintNumbers(params int[] numbers)
{
    Console.WriteLine("PrintNumbers in Array overload");
    foreach (var item in numbers)
    {
        Console.WriteLine(item);
    }
}

private static void PrintNumbers(params ReadOnlySpan<int> numbers)
{
    Console.WriteLine("PrintNumbers in ReadOnlySpan overload");
    foreach (var item in numbers)
    {
        Console.WriteLine(item);
    }
}

输出结果如下:

e13bb232691e59e9a6240b54f3cf0568.png

output

我们来说明一下输出结果,前面两个分别输出了 Array overload 和 ReadOnlySpan overload,因为我们传了具体的类型,所以编译器会优先找类型匹配的重载,所以分别找到了 Array 和 ReadOnlySpan 的方法重载

接着后面的两个调用使用 params collection 特性,因为没有指定特定的类型,所以编译器优先选择了 ReadOnlySpan 的重载来尽量使用性能更好的版本

接着我们来添加一个 OverloadResolutionPriorityAttribute 试一下, 我们来新加两个方法以便于和之前的代码对比

[OverloadResolutionPriority(1)]
private static void PrintNumbers1(params int[] numbers)
{
    Console.WriteLine("PrintNumbers1 in Array overload");
    foreach (var item in numbers)
    {
        Console.WriteLine(item);
    }
}

private static void PrintNumbers1(params ReadOnlySpan<int> numbers)
{
    Console.WriteLine("PrintNumbers1 in ReadOnlySpan overload");
    foreach (var item in numbers)
    {
        Console.WriteLine(item);
    }
}

这里我们针对数组的方法重载添加了一个 OverloadResolutionPriority(1) 的 attribute,我们再来测试一下

PrintNumbers1(1, 2, 3);
PrintNumbers1([1, 2, 3]);

输出结果如下:

54bb82c31e30802ecb1f6c7bf4213a28.png

OverloadResolutionPriority output

可以看到在添加了 attribute 之后,原来调用 ReadOnlySpan 方法重载的变成了调用数组方法重载

More

OverloadResolutionPriorityAttribute 可以帮助我们告诉编译器选择符合预期的方法重载,应该只在发生重载冲突的时候再考虑使用,非必要不使用,使用了之后最好也要添加一些测试用例来验证是按照自己的预期工作的避免多个 overload 同时使用多个 priority 造成不符合预期的结果

References

  • https://github.com/dotnet/csharplang/issues/7706

  • https://github.com/dotnet/roslyn/issues/74067

  • https://github.com/dotnet/roslyn/issues/74131

  • https://github.com/dotnet/runtime/pull/102176

  • https://github.com/dotnet/runtime/issues/102173

  • https://github.com/dotnet/runtime/blob/v9.0.0-rc.1.24431.7/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/OverloadResolutionPriorityAttribute.cs

  • https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/overload-resolution-priority.md

  • https://github.com/WeihanLi/SamplesInPractice/blob/main/net9sample/CSharp13Samples/OverloadResolutionPrioritySample.cs

  • C# 13 新特性 params collection

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值