为什么 Interlocked.Exchange 触发警告 CS4014?

Why is Interlocked.Exchange triggering warning CS4014?

以下简化示例会生成此编译器警告:

warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

public class TaskInterlockedExchangeTest
{
    private Task _Task;

    public async Task DoSomething()
    {
        Interlocked.Exchange(ref _Task, null);
        await _Task;
    }
}

Interlocked.Exchange 调用的行上发出警告。据我所知 Interlocked.Exchange 不是 async 那么为什么编译器会触发这个警告呢?现在这对我来说没有任何意义,所以我错过了什么?

我们确实将警告视为错误,所以我试图弄清楚如何解决这个问题(除了禁用围绕有问题的代码的警告,我只会将其视为最后的手段)。

这发生在 VS2013(更新 5)上。

更新

我刚刚发现以下内容避免了警告:

public class TaskInterlockedExchangeTest
{
    private Task _Task;

    public async Task DoSomething()
    {
        var t = Interlocked.Exchange(ref _Task, null);
        await _Task;
    }
}

因此只需将结果分配给局部变量就足够了。

您正在呼叫 Interlocked.Exchangegeneric overload:

public static T Exchange<T>(ref T location1, T value)
    where T : class

这意味着调用的结果是 Task。警告按设计工作。它看到您正在调用一个 return 是 Task 的函数,因此可能是异步的,但您没有 await 它的结果。

行:

Interlocked.Exchange(ref _Task, null);

意思如下:

  • _Task 中的内容替换为 null
  • 舍弃之前的值(作为Interlocked.Exchange的return值给你)

下面一行:

await _Task;

很可能相当于:

await null;

并且会繁荣

我说 最有可能,因为极有可能另一个线程将某些内容写入 _Task,而您将要 await

我想你真正想写的代码如下:

public async Task DoSomething()
{
    var task = Interlocked.Exchange(ref _Task, null);

    if (task != null)
        await task;
}

或者,对于 .NET 4.6:

public async Task DoSomething()
    => await (Interlocked.Exchange(ref _Task, null) ?? Task.CompletedTask);

你甚至可以去掉 async:

public Task DoSomething()
    => Interlocked.Exchange(ref _Task, null) ?? Task.CompletedTask;