CA2016:将 CancellationToken 参数转发到采用一个该参数的方法

属性
类型名称 ForwardCancellationTokenToInvocations
规则 ID CA2016
标题 将 CancellationToken 参数转发到采用一个该参数的方法
类别 可靠性
修复是中断修复还是非中断修复 非中断
在 .NET 8 中默认启用 作为建议

原因

此规则查找可以接受 CancellationToken 参数但不传递任何参数的方法调用,并建议将父方法的 CancellationToken 转发给它们。

规则说明

此规则分析将 CancellationToken 作为其最后一个参数的方法定义,然后分析其主体中调用的所有方法。 如果任何方法调用可以接受 CancellationToken 作为最后一个参数,或者具有将 CancellationToken 作为最后一个参数的重载,此规则将建议改用该选项,以确保将取消通知传播到可以侦听它的所有操作。

注意

CancellationToken 类型可用的所有 .NET 版本中,规则 CA2016 都可用。 有关适用版本,请参阅 CancellationToken“适用于”部分

如何解决冲突

可以手动修复冲突,也可以使用 Visual Studio 中提供的代码修复功能。 将出现的灯泡悬停在方法调用旁边并选择建议的更改。

下面的示例演示了两个建议的更改:

Rule CA2016 - Forward the CancellationToken parameter to methods that take one

如果不关心是否将已取消的操作通知转发给下层方法调用,则可禁止显示此规则的冲突。 也可以在 C# 中显式传递 default(在 Visual Basic 中为 Nothing)或 None,以禁止显示规则冲突。

此规则可以检测各种冲突。 下面的示例演示了此规则可检测的情况:

示例 1

此规则建议将 c 参数从 MyMethod 转发到 MyMethodWithDefault 调用,因为该方法定义了一个可选的令牌参数:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithDefault(CancellationToken ct = default)
        {
        }

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithDefault();
        }
    }
}

解决方法:

转发 c 参数:

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithDefault(c);
        }

如果不关心是否要将取消通知转发给下层调用,可以:

显式传递 default

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithDefault(default);
        }

或显式传递 CancellationToken.None

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithDefault(CancellationToken.None);
        }

示例 2

此规则建议将 c 参数从 MyMethod 转发到 MyMethodWithOverload 调用,因为该方法具有接受 CancellationToken 参数的重载:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithOverload()
        {
        }

        public static void MyMethodWithOverload(CancellationToken ct = default)
        {
        }

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithOverload();
        }
    }
}

解决方法:

转发 c 参数:

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithOverload(c);
        }

如果不关心是否要将取消通知转发给下层调用,可以:

显式传递 default

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithOverload(default);
        }

或显式传递 CancellationToken.None

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithOverload(CancellationToken.None);
        }

不冲突的示例

父方法中的 CancellationToken 参数不在最后位置:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithDefault(CancellationToken ct = default)
        {
        }

        public static void MyMethod(CancellationToken c, int lastParameter)
        {
            MyMethodWithDefault();
        }
    }
}

默认方法中的 CancellationToken 参数不在最后位置:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithDefault(CancellationToken ct = default, int lastParameter = 0)
        {
        }

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithDefault();
        }
    }
}

重载方法中的 CancellationToken 参数不在最后位置:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithOverload(int lastParameter)
        {
        }
        public static void MyMethodWithOverload(CancellationToken ct, int lastParameter)
        {
        }

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithOverload();
        }
    }
}

父方法定义了多个 CancellationToken 参数:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithDefault(CancellationToken ct = default)
        {
        }

        public static void MyMethod(CancellationToken c1, CancellationToken c2)
        {
            MyMethodWithDefault();
        }
    }
}

具有默认值的方法定义了多个 CancellationToken 参数:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithDefault(CancellationToken c1 = default, CancellationToken c2 = default)
        {
        }

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithDefault();
        }
    }
}

方法重载定义了多个 CancellationToken 参数:

using System.Threading;

namespace ConsoleApp
{
    public static class MyTestClass
    {
        public static void MyMethodWithOverload(CancellationToken c1, CancellationToken c2)
        {
        }

        public static void MyMethodWithOverload()
        {
        }

        public static void MyMethod(CancellationToken c)
        {
            MyMethodWithOverload();
        }
    }
}

抑制警告

如果只想抑制单个冲突,请将预处理器指令添加到源文件以禁用该规则,然后重新启用该规则。

#pragma warning disable CA2016
// The code that's violating the rule is on this line.
#pragma warning restore CA2016

若要对文件、文件夹或项目禁用该规则,请在配置文件中将其严重性设置为 none

[*.{cs,vb}]
dotnet_diagnostic.CA2016.severity = none

有关详细信息,请参阅如何禁止显示代码分析警告