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

Chr*_*Wue 2 c# compiler-warnings task-parallel-library visual-studio-2013

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

警告CS4014:由于未等待此调用,因此在完成调用之前,将继续执行当前方法.考虑将'await'运算符应用于调用的结果.

public class TaskInterlockedExchangeTest
{
    private Task _Task;

    public async Task DoSomething()
    {
        Interlocked.Exchange(ref _Task, null);
        await _Task;
    }
}
Run Code Online (Sandbox Code Playgroud)

通过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;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,简单地将结果分配给局部变量就足够了.

Luc*_*ski 6

我们在调用泛型重载Interlocked.Exchange:

public static T Exchange<T>(ref T location1, T value)
    where T : class
Run Code Online (Sandbox Code Playgroud)

这意味着通话的结果是a Task.警告按设计工作.它看到你正在调用一个返回a的函数Task,因此可能是异步的,但你不是await它的结果.

这条线:

Interlocked.Exchange(ref _Task, null);
Run Code Online (Sandbox Code Playgroud)

意味着以下内容:

  • 更换任何在_Tasknull
  • 扔掉以前的值(给你作为返回值Interlocked.Exchange)

以下行:

await _Task;
Run Code Online (Sandbox Code Playgroud)

最有可能相当于:

await null;
Run Code Online (Sandbox Code Playgroud)

并将蓬勃发展.

最有可能说,因为有一个很小的可能性,另一个线程写了一些东西_Task,你会去await那.

我想你要编写的真实代码如下:

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

    if (task != null)
        await task;
}
Run Code Online (Sandbox Code Playgroud)

或者,使用.NET 4.6:

public async Task DoSomething()
    => await (Interlocked.Exchange(ref _Task, null) ?? Task.CompletedTask);
Run Code Online (Sandbox Code Playgroud)

你甚至可以摆脱async:

public Task DoSomething()
    => Interlocked.Exchange(ref _Task, null) ?? Task.CompletedTask;
Run Code Online (Sandbox Code Playgroud)