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

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

问题描述

注意:我在 Unity 中使用 C#,这意味着版本 .NET 3.5,所以我不能使用 awaitasync 关键字..

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.

wcDispose() 会在正确的时间被调用而不会出现任何问题吗?

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

如果不是,我该如何纠正这个例子?

If not, how do I correct this example?

推荐答案

来自评论:

那我该如何避免呢?只需添加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() 方法,因为这至少会简化实现,使得保留 using 语句变得简单.

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;
}

这样就可以开始下载了,调用你的另外两个方法,然后代码会等待下载完成.只有当它完成时,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.


如果由于某种原因你不能使用 await,那么你将不得不使用一些替代机制来延迟 WebClient 的处理.有些方法将允许您继续使用 using,其他方法将要求您在 DownloadXXXCompleted 事件处理程序中调用 Dispose().如果没有更完整的代码示例,以及为什么 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.


由于您已确认您无法访问当前代码中的 await,这里有几个与旧代码兼容的其他选项…

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);
    }
}

(注意:可以使用上述任何合适的同步,例如 ManualResetEventCountdownEvent,甚至 Semaphore 和/或超薄"等价物.我使用 Monitor 仅仅是因为它的简单性和效率,并且认为读者可以调整以适应他们喜欢的同步方式.一个显而易见的原因是人们可能更喜欢其他Monitor 相比,其他类型的同步技术不会冒着 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 线程中启动的,并且在操作期间不应阻塞该线程.在这种情况下,您将希望完全放弃 using 并从完成事件处理程序中调用 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天全站免登陆