如何写一个“等待”的方法?

我终于看到了asynchronous和等待关键字,这是我得到的,但所有我见过的例子调用.net框架中的asynchronous方法,例如这个调用HttpClient.GetStringAsync()

我不清楚的是这样一种方法,以及如何写我自己的“等待”的方法。 是不是像包装我想在任务中asynchronous运行的代码一样简单并返回?

这很简单

 Task.Run(() => ExpensiveTask()); 

使之成为一种等待的方法:

 public Task ExpensiveTaskAsync() { return Task.Run(() => ExpensiveTask()); } 

这里重要的是要返回一个任务。 该方法甚至不需要标记为asynchronous。 (刚刚阅读了一些进一步的图片)

现在这可以被称为

 async public void DoStuff() { PrepareExpensiveTask(); await ExpensiveTaskAsync(); UseResultsOfExpensiveTask(); } 

请注意,此处的方法签名表示async ,因为该方法可能会将控制权返回给调用方,直到ExpensiveTaskAsync()返回。 而且,在这种情况下,昂贵的手段意味着费时,就像networking请求或类似的一样。 为了将繁重的计算发送到另一个线程,通常最好使用“旧”方法,即System.ComponentModel.BackgroundWorker用于GUI应用程序或System.Threading.Thread

我如何写自己的“等待”方法? 是不是像包装我想在Taskasynchronous运行的代码一样简单并返回?

这是一种select,但它很可能不是你想要做的,因为它实际上并没有给你很多asynchronous代码的好处。 有关更多详细信息,请参阅Stephen Toub的“ 我应该公开同步方法的asynchronous封装?

一般来说,方法不是等待的, types是。 如果您希望能够像await MyMethod()一样写await MyMethod() ,那么MyMethod()必须返回TaskTask<T>或自定义awaittypes。 使用自定义types是一种罕见的高级scheme; 使用Task ,你有几个select:

  • 写你的方法使用asyncawait 。 这对于asynchronous构成动作非常有用,但不能用于最内部await调用。
  • 使用Task中的某个方法Task.Run()Task.Run()Task.FromAsync()创buildTask
  • 使用TaskCompletionSource 。 这是最通用的方法,它可以用来创build任何将来会发生的await方法。

…我将如何写自己的“等待”方法。

返回Task不是唯一的方法。 你可以select创build一个自定义的awaiter (通过实现GetAwaiterINotifyCompletion ),这里有一个伟大的读: “等待什么” 。 返回自定义等待器的.NET API示例: Task.Yield()Dispatcher.InvokeAsync

我在这里和这里有一些自定义的等待者的post,例如:

 // don't use this in production public static class SwitchContext { public static Awaiter Yield() { return new Awaiter(); } public struct Awaiter : System.Runtime.CompilerServices.INotifyCompletion { public Awaiter GetAwaiter() { return this; } public bool IsCompleted { get { return false; } } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem((state) => ((Action)state)(), continuation); } public void GetResult() { } } } // ... await SwitchContext.Yield(); 

是的,从技术上讲,您只需要从async方法中返回一个TaskTask<Result>来实现一个等待方法。

这支持基于任务的asynchronous模式

然而,有几种实施TAP的方法。 有关详细信息,请参阅实现基于任务的asynchronous模式

(但是,当然,所有这些实现仍然会返回TaskTask<Result> )。

只需将您的方法转换为任务。 像@Romiox我通常使用这个扩展

  public static partial class Ext { #region Public Methods public static Task ToTask(Action action) { return Task.Run(action); } public static Task<T> ToTask<T>(Func<T> function) { return Task.Run(function); } public static async Task ToTaskAsync(Action action) { await Task.Run(action); } public static async Task<T> ToTaskAsync<T>(Func<T> function) { return await Task.Run(function); } #endregion Public Methods } 

现在让我们说你有

void foo1()

void foo2(int i1)

int foo3()

int foo4(int i1)

…然后你可以声明你的[asynchronous方法]像@ Romiox

 async Task foo1Async(){ return await Ext.ToTask(()=>foo1()); } async Task foo2Async(int i1){ return await Ext.ToTask(()=>foo2(i1)); } async Task<int> foo3Async(){ return await Ext.ToTask(()=>foo3()); } async Task<int> foo4Async(int i1){ return await Ext.ToTask(()=>foo4(i1)); } 

要么

 async Task foo1Async(){ return await Ext.ToTaskAsync(()=>foo1()); } async Task foo2Async(int i1){ return await Ext.ToTaskAsync(()=>foo2(i1)); } async Task<int> foo3Async(){ return await Ext.ToTaskAsync(()=>foo3()); } async Task<int> foo4Async(int i1){ return await Ext.ToTaskAsync(()=>foo4(i1)); } 

现在你使用asynchronous并等待任何fooAsync例如foo4Async

  async Task<int> TestAsync() { ///Initial Code int m=3; ///Call the task var X =foo4Async(m); ///Between ///Do something while waiting comes here ///.. var Result =await X; ///Final ///Some Code here return Result; }