2013-11-26 5 views
3

Пожалуйста, обратите внимание на следующий тривиальный .NET 4.5 код:Как сохранить состояние задачи при Unwrapping

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!"); 

Последнее утверждение терпит неудачу, который ломает мой код (немного меньше, чем надуманный этот образец).

Мой вопрос заключается в том, как заставить задачу выжить в процессе разворачивания? Есть ли способ вручную развернуть с сохранением состояния?

ответ

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); 
    } 
+0

Я не думаю, что ваш пользовательский Unwrap имеет ту же семантику распространения ошибки. Кроме того, это кажется хорошим решением. – usr

+0

Я был бы рад улучшить его. Какие-либо предложения? – mark