CA2016: Forward the CancellationToken parameter to methods that take one

Value
Type name ForwardCancellationTokenToInvocations
Rule ID CA2016
Category Reliability
Fix is breaking or non-breaking Non-breaking

Cause

This rule locates method invocations that could accept a CancellationToken parameter, but are not passing any, and suggests to forward the parent method's CancellationToken to them.

Rule description

This rule analyzes method definitions that take a CancellationToken as their last parameter, then analyzes all methods invoked in its body. If any of the method invocations can either accept a CancellationToken as the last parameter, or have an overload that takes a CancellationToken as the last parameter, then the rule suggests using that option instead to ensure that the cancellation notification gets propagated to all operations that can listen to it.

Note

Rule CA2016 is available in all .NET versions where the CancellationToken type is available. For the applicable versions, see the CancellationToken "Applies to" section.

How to fix violations

You can either fix violations manually, or use the code fix available in Visual Studio. Hover the light bulb that appears next to the method invocation and select the suggested change.

The following example shows two suggested changes:

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

It's safe to suppress a violation of this rule if you're not concerned about forwarding the canceled operation notification to lower method invocations. You can also explicitly pass default in C# (Nothing in Visual Basic) or None to suppress the rule violation.

The rule can detect a variety of violations. The following examples show cases that the rule can detect:

Example 1

The rule will suggest forwarding the c parameter from MyMethod to the MyMethodWithDefault invocation, because the method defines an optional token parameter:

using System.Threading;

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

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

Fix:

Forward the c parameter:

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

If you are not concerned about forwarding cancellation notifications to lower invocations, you can either:

Explicitly pass default:

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

Or explicitly pass CancellationToken.None:

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

Example 2

The rule will suggest forwarding the c parameter from MyMethod to the MyMethodWithOverload invocation, because the method has an overload that takes a CancellationToken parameter:

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();
        }
    }
}

Fix:

Forward the c parameter:

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

If you are not concerned about forwarding cancellation notifications to lower invocations, you can either:

Explicitly pass default:

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

Or explicitly pass CancellationToken.None:

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

Non-violation examples

The CancellationToken parameter in the parent method is not in the last position:

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();
        }
    }
}

The CancellationToken parameter in the default method is not in the last position:

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();
        }
    }
}

The CancellationToken parameter in the overload method is not in the last position:

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();
        }
    }
}

The parent method defines more than one CancellationToken parameter:

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();
        }
    }
}

The method with defaults defines more than one CancellationToken parameter:

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();
        }
    }
}

The method overload defines more than one CancellationToken parameter:

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();
        }
    }
}

Suppress a warning

If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.

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

To disable the rule for a file, folder, or project, set its severity to none in the configuration file.

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

To disable this entire category of rules, set the severity for the category to none in the configuration file.

[*.{cs,vb}]
dotnet_analyzer_diagnostic.category-Reliability.severity = none

For more information, see How to suppress code analysis warnings.