在非异步方法中调用可等待方法是否可行?

41
在一个使用C#/XAML的Windows 8应用程序中,有时我想从非异步方法调用可等待方法。
实际上,正确的是将其替换为:
  public async Task<string> MyCallingMethod()
  {
      string result = await myMethodAsync();
      return result;
  }

通过这个:

   public string MyCallingMethod()
   {
       Task.Run(async () => {
            string result = await myMethodAsync();
            return result;
             });
   }

对我来说的优点是,我可以在不使用await的情况下使用MyCallingMethod,但这是否正确呢? 如果我想要传递一个ref参数给MyCallingMethod,那么这可能是一个优点,因为在异步方法中不可能有ref参数。


不行。你的匿名异步函数将无法将值返回给外部函数。 - Denis
2个回答

65

在非异步方法中,您可以异步启动任务而不等待结果:

public void MyCallingMethod()
{
    Task t = myMethodAsync();
}

或者您可以附加ContinueWith事件处理程序,该处理程序在完成任务后调用。

public void MyCallingMethod()
{
    myMethodAsync().ContinueWith(
        result =>
        {
            // do stuff with the result
        });
}

或者您可以同步地从任务中获取结果:

public string MyCallingMethod()
{
    string result = myMethodAsync().Result;
    return result;
}

26

如果你在UI线程上尝试这样做,那么你会阻塞线程,因此真的不应该这样做。相反,你应该绕过ref参数,例如接受一个简单类类型的参数,该参数包含你想要更改的值。

另一个不建议这样做的原因是,它仍然无法让你使用ref参数,因为lambda表达式不能访问封闭方法的ref参数。

但是,如果你真的想这样做(我真的认为你不应该这样做),那么你需要获取Task的结果。例如:

public string MyCallingMethod()
{
    var task = Task.Run(async () =>
    {
        return await myMethodAsync();
    });
    return task.Result;
}

不错,自我解决任务并返回结果。谢谢。 - DRapp
1
这样做可以避免主线程在.Result或Wait()上阻塞而导致死锁吗?你的做法和调用var res = myMethodAsync().Result有什么区别? - Stack Undefined

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