C# 语句使用中的异步方法
注意:我在Unity中使用C,这意味着.NET版本3.5,因此我不能使用C# 语句使用中的异步方法,c#,asynchronous,unity3d,.net-3.5,using,C#,Asynchronous,Unity3d,.net 3.5,Using,注意:我在Unity中使用C,这意味着.NET版本3.5,因此我不能使用wait或async关键字 当我在语句中放入一个异步工作的方法时,使用语句会发生什么 using (WebClient wc = new WebClient()) { wc.DownloadFileAsync(urlUri, outputFile); } SomeMethod1(); SomeMethod2(); 如您所知,在调用方法DownloadFileAsync()后,将调用SomeMethod1(),该方法
wait
或async
关键字
当我在语句中放入一个异步工作的方法时,使用语句会发生什么
using (WebClient wc = new WebClient()) {
wc.DownloadFileAsync(urlUri, outputFile);
}
SomeMethod1();
SomeMethod2();
如您所知,在调用方法DownloadFileAsync()
后,将调用SomeMethod1()
,该方法在使用块之外,而DownloadFileAsync()
仍在工作。所以现在我真的很困惑,在这种情况下,using语句和异步方法会发生什么
是否会在正确的时间调用wc
的Dispose()
,而不会出现任何问题
如果没有,如何更正此示例?来自注释:
那我怎么避免呢?只需添加等待关键字
不,你不能这么做。(这就是为什么之前提出的重复问题事实上不是重复的…您的场景有细微的不同。)您需要延迟dispose,直到下载完成,但这是复杂的,因为您需要执行两个以上的程序语句(至少…没有它,无法确定)
我确实认为您应该切换到等待的方法,因为这至少会简化实现,使使用
语句保留变得简单
您可以通过捕获返回的任务
对象来解决问题的另一部分,并且在执行其他程序语句之前不等待它:
using (WebClient wc = new WebClient()) {
Task task = wc.DownloadFileTaskAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
await task;
}
这样,就可以开始下载,调用其他两个方法,然后代码将等待下载完成。只有当它完成后,using
块才会退出,从而允许处置WebClient
对象
当然,在当前的实现中,您无疑正在处理一个适当的DownloadXXXCompleted
事件。如果需要,可以继续以这种方式使用对象。但是,一旦您切换到使用await
,最好是在await
之后添加操作完成时需要执行的代码。这将所有与操作相关的代码都保存在一个地方,并简化了实现
如果出于某种原因,您无法使用等待
,则必须使用某种替代机制来延迟处置网络客户端
。有些方法将允许您继续使用使用
,其他方法将要求您在DownloadXXXCompleted
事件处理程序中调用Dispose()
。如果没有一个更完整的代码示例,也没有一个关于为什么await
不合适的清晰解释,就不可能确定最佳替代方案是什么
编辑:
由于您已确认在当前代码中没有访问wait
的权限,因此这里有两个与旧代码兼容的其他选项
一种可能是在启动操作后在同一线程中等待:
using (WebClient wc = new WebClient()) {
object waitObject = new object();
lock (waitObject)
{
wc.DownloadFileCompleted += (sender, e) =>
{
lock (waitObject) Monitor.Pulse(waitObject);
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
Monitor.Wait(waitObject);
}
}
(注意:可以使用上面任何合适的同步,例如ManualResetEvent
,CountdownEvent
,甚至信号灯
和/或“slim”等价物。我之所以使用Monitor
,仅仅是因为它的简单性和效率,并且想当然地认为读者可以调整以适应他们喜欢的同步方式。人们可能更喜欢Monitor
以外的其他类型的同步技术的一个明显原因是,其他类型的同步技术不会有的风险ode>DownloadFileCompleted
事件处理程序本身阻止等待SomeMethod1()
和SomeMethod2()
方法完成。这是否重要当然取决于与文件下载相比,这些方法调用需要多长时间。)
但是,上述操作将阻止当前线程。在某些情况下,这可能没问题,但大多数情况下操作是在UI线程中启动的,并且在操作期间不应阻塞该线程。在这种情况下,您将希望放弃使用,只需从完成事件处理程序调用Dispose()
:
WebClient wc = new WebClient();
wc.DownloadFileCompleted += (sender, e) =>
{
wc.Dispose();
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
System.Net.WebClient
提供事件DownloadFileCompleted
。您可以为该事件添加一个处理程序,然后在此时处置客户端。这将不起作用。将wait
与*taskancy
@JasonEvans一起使用,你为什么说是?由于OP没有使用wait
,因此出现了一个问题。非常感谢您的回复,我犯了好几次愚蠢的错误。。那我怎么避免呢?只需添加wait关键字?因为OP没有使用返回任务的异步方法,所以Mjolnir'ed副本没有什么用处。复制的OP是偶然的,因为他们不知道他们只需要在方法中使用async/await。对于@JenixGuy,如果您能够使用WebClient.DownloadFileTaskAsync()
您可以使用副本中建议的内容。只需添加wait关键字
如果您知道wait做了什么,答案对您来说是显而易见的。当您不确定关键字的作用时,不要向代码中添加关键字。我刚刚发现关键字wait不能用于3.5版Unity3D正在使用的。。但是,你的回答很有帮助!非常感谢你!很好。特别是最后一个非常简单和干净!:)是的!这是我能选择的最好的方式之一,谢谢!