由于C#的Task是一个类,你显然无法将Task<TDerived>
转换为Task<TBase>
。
但是,你可以这样做:
public async Task<TBase> Run() {
return await MethodThatReturnsDerivedTask();
}
我是否可以调用一个静态任务方法来获取Task<TDerived>
实例,该实例基本上只指向底层任务并转换结果?我喜欢这样的东西:
public Task<TBase> Run() {
return Task.FromDerived(MethodThatReturnsDerivedTask());
}
这种方法存在吗?是否仅为此目的使用异步方法有任何开销?
答案 0 :(得分:39)
这种方法存在吗?
没有
仅为此目的使用异步方法是否有任何开销?
是。但这是最简单的解决方案。
请注意,更通用的方法是Task
的扩展方法,例如Then
。 Stephen Toub探讨了这个in a blog post,我最近incorporated it into AsyncEx。
使用Then
,您的代码如下所示:
public Task<TBase> Run()
{
return MethodThatReturnsDerivedTask().Then(x => (TBase)x);
}
另一种略微减少开销的方法是创建自己的TaskCompletionSource<TBase>
并使用派生结果完成(在我的AsyncEx库中使用TryCompleteFromCompletedTask
):
public Task<TBase> Run()
{
var tcs = new TaskCompletionSource<TBase>();
MethodThatReturnsDerivedTask().ContinueWith(
t => tcs.TryCompleteFromCompletedTask(t),
TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
或(如果您不想依赖AsyncEx):
public Task<TBase> Run()
{
var tcs = new TaskCompletionSource<TBase>();
MethodThatReturnsDerivedTask().ContinueWith(t =>
{
if (t.IsFaulted)
tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(t.Result);
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
答案 1 :(得分:16)
这种方法存在吗?是否仅为此目的使用异步方法有任何开销?
没有内置方法,这确实会导致开销。
“最轻的”替代方案是使用TaskCompletionSource<T>
为此创建新任务。这可以通过像这样的扩展方法来完成:
static Task<TBase> FromDerived<TBase, TDerived>(this Task<TDerived> task) where TDerived : TBase
{
var tcs = new TaskCompletionSource<TBase>();
task.ContinueWith(t => tcs.SetResult(t.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t => tcs.SetException(t.Exception.InnerExceptions), TaskContinuationOptions.OnlyOnFaulted);
task.ContinueWith(t => tcs.SetCanceled(), TaskContinuationOptions.OnlyOnCanceled);
return tcs.Task;
}
答案 2 :(得分:1)
你可以试试这个:
task.ContinueWith<TDerived>( t => (TDerived)t.Result);