2

这段代码,没有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 会导致这个问题?

4

2 回答 2

9

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

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

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

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

更好的是,根据Slack 的建议,您可以使用适当异步的方法,而不是在线程池线程中使用同步方法。这样做可以让您利用操作系统的能力来通知您网络请求的完成,而不会浪费线程池的资源,因为它坐在那里什么都不做。

于 2013-11-01T17:14:10.660 回答
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);
    }
});
于 2013-11-01T17:09:43.027 回答