构建期间未发出编译器警告CS4014

时间:2016-10-05 09:52:16

标签: c# visual-studio roslyn

当被调用方法位于引用的程序集中时,编译器警告CS4014(在不等待结果的情况下调用异步方法)不会在构建期间作为警告发出。

当被调用的方法在相同的程序集中时,会​​正确发出警告。

当两个项目都包含在同一解决方案中时,编译器警告中发出信号。

差异似乎是由于编译器只有编译的引用程序集和Visual Studio都有两个程序集的源代码。

问题是:为什么会有这两种不同的行为?是否有任何方法可以在编译期间发出CS4014警告?

要复制此行为,请设置两个类库,两个类都有一个代码文件:

TestClassLibrary1

public class Class1
{
    public static async Task<string> DoSomething()
    {
        return await Task.FromResult("test");
    }
}

TestClassLibrary2 (引用TestClassLibrary1)

public class Class2
{
    public void CallingDoSomething()
    {
        Class1.DoSomething();
    }
}

编译这些项目将在没有警告的情况下完成。在Visual Studio中使用相同的解决方案打开它们将导致错误列表中显示1错误,Class1.DoSomething()下显示红色波浪线。

1 个答案:

答案 0 :(得分:4)

async修饰符允许您编写更方便地返回Task的代码(使用await),但它在IL * 中没有任何表示。在已编译的程序集中,该方法对编译器看起来只是public static Task<string> DoSomething,并且在不等待其结果的情况下调用它们不会触发警告(即使方法存在于同一程序集中)。将Class1.DoSomething替换为返回任务且应该等待的其他内容(比如Task.Delay(2000)),您同样会看到编译器没有发出警告。但是,当所有源代码都可用时,编译器(以及编译器,我的意思是Roslyn)可以将方法标识为async,因为修饰符仍然是语法树的一部分。

那么为什么编译器在调用返回Task而不使用结果的方法时总是会发出警告,无论它是否恰好使用async编写?好问题。虽然有很多合法的场景,你不等待等待Task(因为你想将它传递给Task.WhenAll)所有这些都涉及将Task存储在其他地方,这不会引起警告。调用一个返回Task并完全丢弃结果的方法几乎肯定是一个错误(当它是故意的时候,有elegant ways抑制警告),这就是为什么这个警告首先存在的原因

我怀疑这个警告的实现可以使用调整(或替换为新警告),但只有编译器的人才会知道这一点。

*:实际上并非如此; async方法将AsyncStateMachineAttribute应用于它们,以便更方便地进行调试。但是,无论出于何种原因,编译器都不会使用它来识别程序集中的async方法。也不应该这样说:async方法返回的Task并没有什么特别之处。但是如果他们想要完全保留CS4104的语义(如果async方法的结果未被使用则发出警告),这将是一种方法。