将Task转换为Task<;单位>;
本文关键字:Task 单位 gt lt 转换 | 更新日期: 2023-09-27 18:27:14
我有一个高通量排队安排,通过它我接收一个Func<Task>
,并希望将其投影到Func<Task<System.Reactive.Unit>>
,以很好地适应下游Rx系统。
由于Unit.Default
是唯一的值,所以感觉这应该很容易,但我希望它尽可能高效。我希望以正确的方式通过原始Task
的所有例外。
我目前的做法是:
public Task<Unit> QueueTaskRx(Func<Task> task)
{
Func<Task<Unit>> f = async () =>
{
await task();
return Unit.Default;
};
return QueueTask(f);
}
但我担心async/await
的开销
也许另一种更有效的方法是:
public Task<Unit> QueueTaskRx(Func<Task> task)
{
Func<Task<Unit>> f = () => task().ContinueWith(_ =>
{
// What other cases do I need to consider here??
if (_.IsFaulted && _.Exception != null)
throw _.Exception.InnerException;
return Unit.Default;
}, TaskContinuationOptions.ExecuteSynchronously);
return QueueTask(f);
}
但这感觉不那么安全,而且更复杂,分支等
有人有更好的方法吗?
我将使用async
/await
,同时添加一个ConfigureAwait(false)
。
可以使用ContinueWith
来,但这只会为您节省一些非常小的时间(比如单个位标志检查和单个引用副本)。这将花费大量的复杂性:
ContinueWith
应始终指定一个TaskScheduler
- 除了例外情况外,您还应该处理取消,因为
Task
对此进行了特殊处理
关于其他陷阱,请参阅我的Task
之旅博客系列(遗憾的是,该系列仍然不完整),我试图列举使用"旧"API可能导致的所有问题(例如,ContinueWith
)。
我在这里实现了您所需要的。我使用了另一个名为Then
的任务扩展,它的灵感来自Stephen Toub的博客文章。