如何编写 C# 5 的异步代码?

3
我有以下场景: 当输入命令时(测试时是控制台应用程序,准备好后希望它成为 WebService),我执行一些代码,并且当需要进一步的用户输入时,我立即返回到命令解释器。当给出新的输入时,我希望处理从我离开的地方继续进行。这听起来很像 C#5 的异步等待模式,所以我决定尝试一下。 我考虑了这个:
public void CommandParser()
{
   while(true)
   { 
      string s = Console.ReadLine();
      if (s == "do_something")
         Execute();
      else if (s == "give_parameters")
         SetParameters();
      //... 
   }
}
MySettings input;
public async void Execute()
{
  //do stuff here
  MyResult result = null
  if (/*input needed*/){
     input = new MySetting();
     result = await input.Calculate();
  }
  else { /* fill result synchronously*/}
  //do something with result here

}

public void SetParameters()
{
   if (input!=null)
      input.UseThis("something"); //now it can return from await
}

现在我的问题是,如何编写 MySettings.Calculate 和 MySettings.UseThis?如何从第一个方法返回一个 Task 并从第二个方法发出就绪信号?我尝试了许多 Task 工厂方法,但找不到正确的方法!请帮忙!

这与您的问题不直接相关,但是您如何拥有C# 5? - soandos
1个回答

6

一种选择是使用TaskCompletionSource<T>。这将为您构建一个任务,您可以在源上调用SetResultSetException,从而适当地通知任务。

这就是我用来为Eduasync实现AsyncTaskMethodBuilder<T>的方法 - 所以你可以看看那个例子。

您需要预先设置TaskCompletionSource或执行其他协调工作,以使和都知道相同的对象 - 但然后Calculate将只返回completionSource.Task,而UseThis将调用completionSource.SetResult

请记住,当您调用SetResult时,异步方法将继续在不同的线程池线程上进行(如果您正在使用控制台应用程序(或Web服务)) - 因此,您无疑希望为主循环创建一个不同的TaskCompletionSource,以便下一轮使用。


谢谢,看起来非常有前途。我会尝试实现我的实际代码,然后再回来确认。 - TDaver
虽然很快的一个问题,但是我已经安装了 CTP,但是 await 似乎无法编译。我做错了什么? - TDaver
@TDaver:你遇到了什么错误?如果CTP安装干净,编译器应该已经相应地更改了... - Jon Skeet
我后来发现我的问题是安装了一些sp1后更新,这会阻止async ctp的正常运行。但我不知道是哪个更新,所以现在我正在卸载我能找到的每一个.net和vs更新... - TDaver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接