C# 语句使用中的异步方法

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(),该方法

注意:我在Unity中使用C,这意味着.NET版本3.5,因此我不能使用
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正在使用的。。但是,你的回答很有帮助!非常感谢你!很好。特别是最后一个非常简单和干净!:)是的!这是我能选择的最好的方式之一,谢谢!