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

时间:2013-11-01 17:04:46

标签: 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 }

这段代码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 }

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

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

2 个答案:

答案 0 :(得分:8)

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

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

至于实际代码,它已在dcastro's answer中提供:

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

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

答案 1 :(得分:3)

使用允许您返回对象的StartNew重载: http://msdn.microsoft.com/en-us/library/dd321455(v=vs.110).aspx

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