返回介绍

如何:解除嵌套任务的包装

发布于 2025-02-23 23:16:16 字数 7748 浏览 0 评论 0 收藏 0

你可以返回的任务从方法返回,然后等待或继续从该任务,如下面的示例中所示:

static Task<string> DoWorkAsync()
{
  return Task<String>.Factory.StartNew(() =>
  {
     //...
    return "Work completed.";
  });
}

static void StartTask()
{
  Task<String> t = DoWorkAsync();
  t.Wait();
  Console.WriteLine(t.Result);
}
 Shared Function DoWorkAsync() As Task(Of String)

   Return Task(Of String).Run(Function()
                 '...
                 Return "Work completed."
                End Function)
End Function

Shared Sub StartTask()

   Dim t As Task(Of String) = DoWorkAsync()
   t.Wait()
   Console.WriteLine(t.Result)
End Sub

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

但是,在某些情况下,你可能想要创建另一个任务中的任务,然后返回嵌套的任务。 在这种情况下, TResult 的封闭任务本身就是一项任务。 在以下示例中,结果属性是 Task<Task<string>> 在 C# 或 Task(Of Task(Of String)) 在 Visual Basic 中。

// 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>> ( Task(Of Task)Task(Of Task(Of TResult)) 在 Visual Basic 中) 到 TaskTask<TResult> ( Task(Of TResult) 在 Visual Basic 中)。 新任务完全表示内部的嵌套的任务,并包括取消状态,以及所有异常。

示例

下面的示例演示如何使用 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( (antecedant) =>
        {
          if (antecedant.Result >= threshold)
          {
            return Task.Factory.StartNew( () =>  Console.WriteLine("Program complete. Final = 0x{0:x} threshold = 0x{1:x}", stepTwo.Result, threshold));
          }
          else
          {
            return DoSomeOtherAsyncronousWork(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 DoSomeOtherAsyncronousWork(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)
                        Else
                          Return DoSomeOtherAsynchronousWork(stepTwo.Result, threshold)
                        End If
                      End Function)
    Try
      lastStep.Wait()
    Catch ae As AggregateException
      For Each ex As Exception In ae.InnerExceptions
        Console.WriteLine(ex.Message & ex.StackTrace & ex.GetBaseException.ToString())
      Next
    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)
    Next
    Console.WriteLine("Done computing")
    Return final
  End Function
#End Region
End Module

另请参阅

System.Threading.Tasks.TaskExtensions
基于任务的异步编程

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文