Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用async/await时使用未分配的局部变量_C#_Async Await - Fatal编程技术网

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

C# 使用async/await时使用未分配的局部变量,c#,async-await,C#,Async Await,此代码(不带wait)编译: IEnumerable<PingResponse> pingResponses; using (var prestoWcf = new PrestoWcf<IPingService>()) { pingResponses = prestoWcf.Service.GetAllForPingRequest(this.PingRequest); } foreach (PingResponse response in pingRespons

此代码(不带
wait
)编译:

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

foreach (PingResponse response in pingResponses) { // code here }
错误是:
使用未分配的局部变量“pingResponses”


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

使用允许您返回对象的
StartNew
重载:

IEnumerable pingResponses=
等待任务。工厂。开始新建(()=>
{
使用(var prestoWcf=new prestoWcf())
{
返回prestoWcf.Service.GetAllForPingRequest(this.PingRequest);
}
});

它不起作用的原因是编译器无法知道提供给
StartNew
方法的委托总是在执行
foreach
循环之前执行。你知道,我也知道,但编译器无法证明它,因为它目前有明确的可赋值规则

虽然有几种“变通方法”可以诱使编译器允许您这样做,但最好也是最惯用的解决方案是让任务返回一个结果,而不是变异一个闭合变量。这样一来,你就不再依赖于任务的副作用,而是依赖于结果本身。这使得代码更容易推理(任务和使用它的代码可以分别分析,而不是让每个任务的实现相互依赖),并确保不同线程之间共享的内存的正确同步(一个非常重要的任务)

关于实际代码,已在以下文件中提供:

IEnumerable pingResponses=
等待任务。工厂。开始新建(()=>
{
使用(var prestoWcf=new prestoWcf())
{
返回prestoWcf.Service.GetAllForPingRequest(this.PingRequest);
}
});

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

您应该发送一个异步网络请求,而不是在后台线程上发送同步请求。这样就不会浪费线程。您是否有
GetAllForPingRequestsAsync
?看到该类的名称中包含WCF,WCF代理生成工具应该能够自动生成一个代理,该代理返回
任务
(这就是您将如何实现SLaks的建议)@ScottChamberlain我还没有
GetAllForPingRequestsAsync
。看来我需要这么做。谢谢您的提示。@BobHorn如果您使用
svcutil.exe
生成代理类,请不要添加
/async
/a
/syncOnly
开关,因为这将覆盖默认值,而默认值会使基于任务的异步版本生效。如果您使用的是GUI,请确保选中该框,如果任务的单选按钮需要以较新版本的.NET为目标,或者使用
svcuti
生成代理。我会做两个小更改:1。使用
Task.Run()
而不是
StartNew()
,它比较短,并且总是在线程池上执行工作。2.在这里使用
var
,我认为这里不需要完整类型,但是编译器在原始代码中需要它。
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 }
IEnumerable<PingResponse> pingResponses = 
await Task.Factory.StartNew(() =>
{
    using (var prestoWcf = new PrestoWcf<IPingService>())
    {
        return prestoWcf.Service.GetAllForPingRequest(this.PingRequest);
    }
});
IEnumerable<PingResponse> pingResponses = 
    await Task.Factory.StartNew(() =>
    {
        using (var prestoWcf = new PrestoWcf<IPingService>())
        {
            return prestoWcf.Service.GetAllForPingRequest(this.PingRequest);
        }
    });