使用异步委托进行异常处理
本文关键字:异常处理 异步 | 更新日期: 2023-09-27 18:32:21
我试图弄清楚我在这里做错了什么。我确定这是愚蠢的东西,但我可以用一些额外的眼睛来弄清楚它是什么。我正在尝试创建一个可以向其分配工作操作委托的工作器服务。当我尝试捕获工作操作委托引发的异常时,不会调用处理程序。我认为这是因为我的操作实际上是一个返回 Task 的异步方法,并且没有等待它。但是我怎么知道委托是异步的呢?为什么 C# 允许我将返回 Task 的方法分配给应该返回 void 的操作变量?
任何帮助将不胜感激!
[Fact]
public async Task CanCatchExceptions() {
var worker = new Worker {
WorkAction = async item => await Throws()
};
worker.DoWork(new WorkItem { Id = 1 });
}
public class Worker {
// would prefer to keep work action simple and not require a Task.
public Action<WorkItem> WorkAction { get; set; }
public void DoWork(WorkItem item) {
try {
WorkAction(item);
} catch {
Debug.WriteLine("Handled");
}
}
}
public class WorkItem {
public int Id { get; set; }
}
public async Task Throws() {
throw new ApplicationException();
}
没有返回值的 Lambda 可以强制转换为任务返回方法(例如,Func<Task>
)或 void 返回方法(例如,Action
)。请注意,当强制转换为 void 返回方法时,该 lambda 的实际方法是一种async void
方法,async void
方法附带的所有问题。我在最佳实践文章中描述了async void
的一些问题;其中之一是您无法捕获异常 try
.
最好的选择是更改工作项以返回Task
,这是异步方法的更自然的表示形式。
为什么 C# 允许我将返回 Task 的方法分配给应该返回 void 的操作变量?
由于async void
是异步事件处理程序的合法用例,因此编译器允许 void 返回Action<T>
并且不抱怨。一旦您意识到这一事实,您就可以显式使用Func<Task>
,这将创建所需的Task
返回方法重载。
正如您所说,您希望保持工作操作"简单"并且不需要任务,请考虑提供异步重载,该重载将与异步控制流一起正常运行:
public Func<WorkItem, Task> WorkAsync { get; set; }
public async Task WorkAsync(WorkItem item)
{
try
{
await WorkAsync(item)
}
catch (Exception e)
{
// Handle
}
}
请注意,根据您的选择,这可能属于完全不同的类(将异步工作线程与同步工作线程分开)。