使用async/await时使用未分配的局部变量

Bob*_*orn 1 c# async-await

这段代码没有await编译:

IEnumerable<PingResponse> pingResponses;
using (var prestoWcf = new PrestoWcf<IPingService>())
{
    pingResponses = prestoWcf.Service.GetAllForPingRequest(this.PingRequest);
}

foreach (PingResponse response in pingResponses) { // code here }
Run Code Online (Sandbox Code Playgroud)

这段代码用await,不编译:

IEnumerable<PingResponse> pingResponses;
await Task.Factory.StartNew(() =>
{
    using (var prestoWcf = new PrestoWcf<IPingService>())
    {
        pingResponses = prestoWcf.Service.GetAllForPingRequest(this.PingRequest);
    }
});

foreach (PingResponse response in pingResponses) { // code here }
Run Code Online (Sandbox Code Playgroud)

错误是: Use of unassigned local variable 'pingResponses'

为什么引入async/await会导致此问题?

Ser*_*rvy 8

它不起作用的原因是编译器无法知道提供给StartNew方法的委托将始终在foreach循环之前执行.你知道它,我知道它,但鉴于它当前明确的可分配性规则,编译器无法证明它.

虽然有几个"解决方法"只是欺骗编译器让你这样做,但最好和最惯用的解决方案是让任务返回结果而不是改变一个关闭的变量.这样你就不会依赖任务的副作用,而是依靠结果本身.这使得代码更易于推理(任务和使用它的代码可以单独分析,而不是让每个代理的实现依赖于另一个)并确保在不同线程之间共享的内存的正确同步(一个非平凡的任务) .

至于实际代码,它已经在dcastro的答案中提供:

IEnumerable<PingResponse> pingResponses = 
    await Task.Factory.StartNew(() =>
    {
        using (var prestoWcf = new PrestoWcf<IPingService>())
        {
            return prestoWcf.Service.GetAllForPingRequest(this.PingRequest);
        }
    });
Run Code Online (Sandbox Code Playgroud)

更好的是,根据SLack的建议,您可以使用正确异步的方法,而不是在线程池线程中使用同步方法.这样做可以让您利用操作系统的能力来通知您网络请求的完成,而不会浪费线程池的资源,让它坐在那里无所事事.