展开时如何保留任务状态

时间:2013-11-26 21:31:20

标签: asynchronous .net-4.5

请注意以下简单的.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!");

最后一个断言失败了,这破坏了我的代码(比这个样本稍微做作)。

我的问题是如何使任务状态在展开时生存?有没有办法手动打开状态保存?

1 个答案:

答案 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);
    }
相关问题