请注意以下简单的.NET 4.5代码:
var tcs = new TaskCompletionSource<object>("Hello");
var t1 = tcs.Task;
var t2 = t1.ContinueWith((t, state) => 0, "Hello");
var t3 = t2.ContinueWith((t, state) => new Task<int>(_ => 0, state), "Hello");
var t4 = t3.Unwrap();
Trace.Assert("Hello".Equals(t1.AsyncState), "t1.AsyncState is broken!");
Trace.Assert("Hello".Equals(t2.AsyncState), "t2.AsyncState is broken!");
Trace.Assert("Hello".Equals(t3.AsyncState), "t3.AsyncState is broken!");
Trace.Assert("Hello".Equals(t4.AsyncState), "t4.AsyncState is broken!");
最后一个断言失败了,这破坏了我的代码(比这个样本稍微做作)。
我的问题是如何使任务状态在展开时生存?有没有办法手动打开状态保存?
答案 0 :(得分:2)
现在,我没有看到任何其他选项,除了避免使用默认的Unwrap()
方法。相反,我发现以下解决方法是足够的:
var t4 = t3.ContinueWith((t, _) => t.Result.Result, t3.AsyncState);
我会将其打包为我自己的扩展方法,例如FixedUnwrap()
:
public static Task<TResult> FixedUnwrap<TResult>(this Task<Task<TResult>> task)
{
return task.ContinueWith((t, _) => t.Result.Result, task.AsyncState);
}
重要更新
建议的实施是错误的!完成嵌套任务后,必须继续执行展开的任务,而当包装器任务完成时,给定的版本将继续。这是非常错误的。
请在下面找到正确的(两个版本):
public static Task TaskUnwrap(this Task<Task> task)
{
return task.Unwrap().ContinueWith((t, _) =>
{
if (t.Exception != null)
{
throw t.Exception;
}
}, task.AsyncState);
}
public static Task<TResult> TaskUnwrap<TResult>(this Task<Task<TResult>> task)
{
return task.Unwrap().ContinueWith((t, _) => t.Result, task.AsyncState);
}