【发布时间】:2021-09-29 03:40:24
【问题描述】:
假设我正在开发一个使用具有以下签名的接口的 C# 库,例如:
public interface IMyInterface
{
public void DoWork();
}
我有 2 个不同的类实现这个接口。
- 只运行同步代码(所以
void返回类型就可以了)。 - 需要等待异步调用(因此,理想情况下,我希望
DoWork成为async Task,而不是void)。
非异步类不是问题,因为它确实只需要 void 返回类型:
public class NonAsyncClass : IMyInterface
{
public void DoWork()
{
Console.WriteLine("This is a non-Async method");
}
}
但我正在尝试考虑实现async 类的最佳方法。我正在考虑这样的事情:
public class AsyncClass : IMyInterface
{
public void DoWork()
{
var t = Task.Run(async () => {
await ExternalProcess();
});
t.Wait();
}
}
但感觉这不是正确的做事方式。
当方法需要为async 时,对返回类型为void 的接口(假设您无法控制更改任何接口签名)进行编程的最佳方法是什么?或者反之亦然,当方法没有任何异步代码时,一个程序如何针对asyc Task 返回类型?
【问题讨论】:
-
如果你有
Task没有任何异步代码的返回类型,你可以在你的方法结束时返回Task.CompletedTask(或者如果你有Task<T>,你可以返回Task.FromResult(T result))。但是如果你有void方法并且你想在其中做一些异步的事情,你必须让你的代码同步,就像你用Wait做的那样 -
我想知道的一件事:你真的想使用
Task.Run还是只想做类似ExternalProcess().Result;的事情? -
您应该尽可能避免使用
Wait或GetAwaiter().GetResult()。问题是如果在调用者代码中使用任何类型的同步,它可能会导致死锁,例如Main-Thread 调用该方法,Task.Run中的代码需要与 main 同步以更新 UI。 Main-Thread 可以t invoke that call because its 等待 Task 结束 -> 死锁。尝试将方法设计为Task DoWorkAsync,并在同步实现的情况下返回Taks.CompletedTask。 -
@JohnBustos 你不能做任何其他事情,如果你必须处理
void签名,但我同意@sebastian-schumann 的观点,它一点都不好。 :) -
如果您必须按原样使用接口,您有两个选择: 1. 调用者不需要知道并行发生的事情。只需使用
Task.Run,无需等待任务结束。 2. 异步代码做了一些需要在方法返回之前完成的事情:你必须使用Wait或者更好的GetAwaiter().GetResult()等待。 BTW:如果你处理事件并且你有机会改变界面Stephen Cleary有一个很好的解决方案。
标签: c# asynchronous async-await