在上面的示例中, Result 属性的类型为 string (Visual Basic 中的 String )。

不过,在某些情况下,建议在另一个任务中创建任务,再返回嵌套任务。 在这种情况下,封闭任务的 TResult 本身就是任务。 在下面的示例中,Result 属性是 C# 中的 Task<Task<string>> 或 Visual Basic 中的 Task(Of Task(Of String))

// Note the type of t and t2.
Task<Task<string>> t = Task.Factory.StartNew(() => DoWorkAsync());
Task<Task<string>> t2 = DoWorkAsync().ContinueWith((s) => DoMoreWorkAsync());
// Outputs: System.Threading.Tasks.Task`1[System.String]
Console.WriteLine(t.Result);
' Note the type of t and t2.
Dim t As Task(Of Task(Of String)) = Task.Run(Function() DoWorkAsync())
Dim t2 As Task(Of Task(Of String)) = DoWorkAsync().ContinueWith(Function(s) DoMoreWorkAsync())
' Outputs: System.Threading.Tasks.Task`1[System.String]
Console.WriteLine(t.Result)

虽然可以编写代码来取消包装外部任务并检索原始任务及其 Result 属性,但此类代码不易编写,因为必须处理异常和取消请求。 在这种情况下,建议使用 Unwrap 扩展方法之一,如下面的示例所示。

// Unwrap the inner task.
Task<string> t3 = DoWorkAsync().ContinueWith((s) => DoMoreWorkAsync()).Unwrap();
// Outputs "More work completed."
Console.WriteLine(t.Result);
' Unwrap the inner task.
Dim t3 As Task(Of String) = DoWorkAsync().ContinueWith(Function(s) DoMoreWorkAsync()).Unwrap()
' Outputs "More work completed."
Console.WriteLine(t.Result)

Unwrap 方法可用于将任何 Task<Task>Task<Task<TResult>>(Visual Basic 中的 Task(Of Task)Task(Of Task(Of TResult)))转换为 TaskTask<TResult>(Visual Basic 中的 Task(Of TResult))。 新任务完全表示内部嵌套任务,并包含取消状态和所有异常。

下面的示例展示了如何使用 Unwrap 扩展方法。

namespace Unwrap using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; // A program whose only use is to demonstrate Unwrap. class Program static void Main() // An arbitrary threshold value. byte threshold = 0x40; // data is a Task<byte[]> var data = Task<byte[]>.Factory.StartNew(() => return GetData(); // We want to return a task so that we can // continue from it later in the program. // Without Unwrap: stepTwo is a Task<Task<byte[]>> // With Unwrap: stepTwo is a Task<byte[]> var stepTwo = data.ContinueWith((antecedent) => return Task<byte>.Factory.StartNew( () => Compute(antecedent.Result)); .Unwrap(); // Without Unwrap: antecedent.Result = Task<byte> // and the following method will not compile. // With Unwrap: antecedent.Result = byte and // we can work directly with the result of the Compute method. var lastStep = stepTwo.ContinueWith( (antecedent) => if (antecedent.Result >= threshold) return Task.Factory.StartNew( () => Console.WriteLine("Program complete. Final = 0x{0:x} threshold = 0x{1:x}", stepTwo.Result, threshold)); return DoSomeOtherAsynchronousWork(stepTwo.Result, threshold); lastStep.Wait(); Console.WriteLine("Press any key"); Console.ReadKey(); #region Dummy_Methods private static byte[] GetData() Random rand = new Random(); byte[] bytes = new byte[64]; rand.NextBytes(bytes); return bytes; static Task DoSomeOtherAsynchronousWork(int i, byte b2) return Task.Factory.StartNew(() => Thread.SpinWait(500000); Console.WriteLine("Doing more work. Value was <= threshold"); static byte Compute(byte[] data) byte final = 0; foreach (byte item in data) final ^= item; Console.WriteLine("{0:x}", final); Console.WriteLine("Done computing"); return final; #endregion
'How to: Unwrap a Task
Imports System.Threading
Imports System.Threading.Tasks
Module UnwrapATask2
    Sub Main()
        ' An arbitrary threshold value.
        Dim threshold As Byte = &H40
        ' myData is a Task(Of Byte())
        Dim myData As Task(Of Byte()) = Task.Factory.StartNew(Function()
                                                                  Return GetData()
                                                              End Function)
        ' We want to return a task so that we can
        ' continue from it later in the program.
        ' Without Unwrap: stepTwo is a Task(Of Task(Of Byte))
        ' With Unwrap: stepTwo is a Task(Of Byte)
        Dim stepTwo = myData.ContinueWith(Function(antecedent)
                                              Return Task.Factory.StartNew(Function()
                                                                               Return Compute(antecedent.Result)
                                                                           End Function)
                                          End Function).Unwrap()
        Dim lastStep = stepTwo.ContinueWith(Function(antecedent)
                                                Console.WriteLine("Result = {0}", antecedent.Result)
                                                If antecedent.Result >= threshold Then
                                                    Return Task.Factory.StartNew(Sub()
                                                                                     Console.WriteLine("Program complete. Final = &H{1:x} threshold = &H{1:x}",
                                                                                                       stepTwo.Result, threshold)
                                                                                 End Sub)
                                                    Return DoSomeOtherAsynchronousWork(stepTwo.Result, threshold)
                                                End If
                                            End Function)
            lastStep.Wait()
        Catch ae As AggregateException
            For Each ex As Exception In ae.InnerExceptions
                Console.WriteLine(ex.Message & ex.StackTrace & ex.GetBaseException.ToString())
        End Try
        Console.WriteLine("Press any key")
        Console.ReadKey()
    End Sub
#Region "Dummy_Methods"
    Function GetData() As Byte()
        Dim rand As Random = New Random()
        Dim bytes(64) As Byte
        rand.NextBytes(bytes)
        Return bytes
    End Function
    Function DoSomeOtherAsynchronousWork(ByVal i As Integer, ByVal b2 As Byte) As Task
        Return Task.Factory.StartNew(Sub()
                                         Thread.SpinWait(500000)
                                         Console.WriteLine("Doing more work. Value was <= threshold.")
                                     End Sub)
    End Function
    Function Compute(ByVal d As Byte()) As Byte
        Dim final As Byte = 0
        For Each item As Byte In d
            final = final Xor item
            Console.WriteLine("{0:x}", final)
        Console.WriteLine("Done computing")
        Return final
    End Function
#End Region
End Module
  • System.Threading.Tasks.TaskExtensions
  • 基于任务的异步编程
  •