gpt4 book ai didi

c# - using语句中的异步方法

转载 作者:IT王子 更新时间:2023-10-29 04:27:29 24 4
gpt4 key购买 nike

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

当我在 using 语句 中放入一个异步 工作的方法时会发生什么?

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

如您所知,在方法 DownloadFileAsync() 被调用后, SomeMethod1() 将被调用,它在 using block 之外而 DownloadFileAsync() 仍在工作。所以现在我真的很困惑在这种情况下 using 语句和异步方法会发生什么。

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

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

最佳答案

来自评论:

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

不,你不能只是那样做。 (这就是为什么之前提出的重复问题实际上不是重复的......你的场景略有不同。)你需要延迟处理直到下载完成,但由于你需要执行两个以上的程序语句(至少……如果没有 a good, minimal, complete code example 就不可能确定。

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

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

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

这样就可以开始下载了,调用你另外两个方法,然后代码会等待下载完成。只有当它完成时才会退出 using block ,从而允许释放 WebClient 对象。

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


如果出于某种原因您不能使用 await,那么您将不得不使用一些替代机制来延迟 WebClient 的处理。一些方法将允许您继续使用 using,其他方法将要求您在 DownloadXXXCompleted 事件处理程序中调用 Dispose()。如果没有更完整的代码示例,也没有对为什么 await 不合适的明确解释,则无法确定最佳替代方案是什么。


编辑:

由于您已确认您无权访问当前代码中的 await,因此这里有一些与旧代码兼容的其他选项......

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

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 和/或“ slim ”等价物。我使用 Monitor 只是因为它的简单性和效率,并且理所当然地认为读者可以调整以适应他们喜欢的同步方式。一个明显的原因可能是人们更喜欢 otherMonitor 相比,其他类型的同步技术不会冒 DownloadFileCompleted 事件处理程序本身阻塞等待 SomeMethod1() 的风险SomeMethod2() 方法来完成。这是否重要当然取决于与文件下载相比这些方法调用需要多长时间。)

然而,以上将阻塞当前线程。在某些情况下,这可能没问题,但大多数情况下,操作是在 UI 线程中启动的,并且在操作期间不应阻塞该线程。在这种情况下,您将希望完全放弃 using,而只需从完成事件处理程序中调用 Dispose():

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

关于c# - using语句中的异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33722968/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com