using语句中的异步方法 [英] Asynchronous methods in using statement

查看:192
本文介绍了using语句中的异步方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我在Unity中使用C#,这意味着.NET 3.5 版本,因此我不能使用 await async 关键字。

Note: I'm using C# in Unity, that means version .NET 3.5, so I cannot use await or async keyword..

当我在其中输入有效方法时,使用语句会发生什么异步

What will happen to using statement when I put a method in it which works asynchronously?

using (WebClient wc = new WebClient()) {
    wc.DownloadFileAsync(urlUri, outputFile);
}
SomeMethod1();
SomeMethod2();

您知道,在方法 DownloadFileAsync()被调用, SomeMethod1()将被调用,而 using 块不在 DownloadFileAsync()仍在运行中。所以现在我真的很困惑在这种情况下using语句和异步方法会发生什么。

As you know, after the method DownloadFileAsync() is called, SomeMethod1() will be called which is out of the using block while DownloadFileAsync() is still working. So now I'm really confused what would happen to the using statement and the asynchronous method in this case.

Dispose() wc 中的c $ c>会在正确的时间调用而没有任何问题?

Would Dispose() of wc be called at the right time without any problems?

如果没有,我该怎么办

推荐答案

来自注释:


那我该如何避免呢?只需添加await关键字?

Then how do I avoid this? Just add await keyword?

不,您不能只是这样做。 (这就是为什么以前提出的重复问题实际上并不是重复问题的原因。)您将需要将处置延迟到下载完成之后,但是由于需要执行另外两个程序语句而使情况变得复杂(至少…如果没有一个好的,最小完整代码示例,就不可能确定)。

No, you can't just do that. (And that's why the previously proposed duplicate question was not in fact a duplicate…your scenario is subtly different.) You will need to delay the dispose until the download has completed, but this is complicated by your need to execute two more program statements (at least…it's impossible to know for sure without a good, minimal, complete code example).

认为您应该切换到等待的 WebClient.DownloadFileTaskAsync() 方法,因为这样至少可以简化实现,使使用保留语句变得简单。

I do think you should switch to the awaitable WebClient.DownloadFileTaskAsync() method, as this will at least simplify the implementation, making it simple to retain the using statement.

您可以解决通过捕获返回的 Task 对象,并等到之后等到您的其他程序语句执行后,才等待该问题的另一部分:

You can address the other part of the problem by capturing the returned Task object and not awaiting it until after your other program statements have executed:

using (WebClient wc = new WebClient()) {
    Task task = wc.DownloadFileTaskAsync(urlUri, outputFile);
    SomeMethod1();
    SomeMethod2();
    await task;
}

这样,就可以开始下载了,另外两种方法称为然后 then 该代码将等待下载完成。仅在完成后,才会退出 using 块,从而允许处置 WebClient 对象。

In this way, the download can be started, your other two methods called, and then the code will wait for the completion of the download. Only when it's completed will the using block then be exited, allowing the WebClient object to be disposed.

当然,在您当前的实现中,您无疑正在处理相应的 DownloadXXXCompleted 事件。如果需要,可以继续使用该对象。但是恕我直言,一旦您切换到使用 await ,最好将 await 之后的代码放在后面在操作完成时执行。这样会将与该操作相关的所有代码都放在一个地方,并简化了实现。

Of course, in your current implementation you undoubtedly are handling an appropriate DownloadXXXCompleted event. If you want, you can continue using the object that way. But IMHO once you have switched over to using await, it's much better to just put after the await the code that needs to execute on the completion of the operation. This keeps all of the code relevant to the operation in one place and simplifies the implementation.



如果由于某些原因而无法使用等待,那么您将不得不使用其他替代机制来延迟处置 WebClient 。某些方法将允许您继续使用使用,其他方法则需要您在<$中调用 Dispose() c $ c> DownloadXXXCompleted
事件处理程序。如果没有更完整的代码示例,并且没有清楚地解释为什么 await 不适合的原因,就无法确定最好的替代方案是什么。


If for some reason you can't use await, then you will have to use some alternate mechanism for delaying the dispose of the WebClient. Some approaches will allow you to continue to use using, others will require that you call Dispose() in the DownloadXXXCompleted event handler. Without a more complete code example, and a clear explanation for why await is not suitable, it would not be possible to say for sure what the best alternative would be.



编辑:

由于您已确认您无法在当前代码中访问等待,以下是与旧代码兼容的其他几个选项…

Since you've confirmed that you don't have access to await in the current code, here are a couple of other options compatible with older code…

一种可能性是在开始操作后仅在同一线程中等待:

One possibility is to just wait in the same thread after starting the operation:

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 或什至 Semaphore 和/或超薄等价物。我之所以使用 Monitor 仅仅是因为它的简单性和效率,并认为读者可以调整以适应自己偏爱的同步方式。之所以可能会喜欢 other 而不是的原因是,其他类型的同步技术不会冒 DownloadFileCompleted 事件处理程序本身会阻止等待 SomeMethod1() SomeMethod2()方法的等待当然,这是否重要取决于与文件下载相比,这些方法调用将花费多长时间。)

(Note: one can use any suitable synchronization above, such as ManualResetEvent, CountdownEvent, or even Semaphore and/or "slim" equivalents. I use Monitor simply due to its simplicity and efficiency, and take as granted readers can adjust to accommodate their preferred means of synchronization. One obvious reason one might prefer something other than Monitor is that the other types of synchronization techniques won't run the risk of having the DownloadFileCompleted event handler itself block waiting on the SomeMethod1() and SomeMethod2() methods to complete. Whether this is important depends of course on how long those method calls would take as compared to the file download.)

,阻止当前线程。在某些情况下,这可能很好,但是大多数情况下,该操作是在UI线程中启动的,并且在操作过程中不应阻塞该线程。在这种情况下,您将希望完全放弃使用 ,而只是从完成事件处理程序中调用 Dispose()

The above will, however, block the current thread. In some cases this may be fine, but most often the operation is being initiated in the UI thread, and that thread should not be blocked for the duration of the operation. In that case, you will want to forego using altogether and just call Dispose() from the completion event handler:

WebClient wc = new WebClient();
wc.DownloadFileCompleted += (sender, e) =>
{
    wc.Dispose();
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();

这篇关于using语句中的异步方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆