如何调用异步方法从C#中的同步方法返回void并确保异步方法完成?

时间:2018-01-26 18:24:13

标签: c# asynchronous async-await state

我搜索过StackOverflow并没有找到对我特定情况的明确答案。 我有一个方法:

public async Task InitializeMachine()
{
    await DoSomeWork1();
    // other stuff
    await DoSomeWork2();
    // other stuff
}

请注意,它返回的签名是Task,而不是Task<T>。很难(如果不是不可能的话)重写这样的所有方法。 我想从同步方法调用此方法并让它等待InitializeMachine方法完全完成。同样,很难将其更改为异步方法(我将在下面为感兴趣的人描述原因)。 我查看了一些相关的问题和参考资料,例如:

https://msdn.microsoft.com/en-us/magazine/mt238404.aspx

await works but calling task.Result hangs/deadlocks

How to call asynchronous method from synchronous method in C#?

答案看起来很旧(也许还有更好的方法?)至少在很多情况下,它们似乎依赖于返回Task<T>的异步方法,而不仅仅是Task。 我有

void Initialize()
{
    //InitializeMachine(); // Perfectly legal, but will return at first await
     //return Task.Run(() => InitializeMachine()).GetAwaiter().GetResult();  // can't get this to compile. My typo? Or because it's Task not Task<T> ? This is the "Thread Pool Hack" in first reference above by Stephen Cleary
     var task = Task.Run(() => InitializeMachine()); // these 2 lines work!
        task.Wait();  // but see heated argument in 2nd reference in the answer by Herman Schoenfeld. Is it safe?
        Task task = Task.Run(async () => await InitializeMachine()); // also works. Comes from 3rd reference by author "Tohid"

}

有人可以告诉我应该使用哪种方法以及为什么?正如我所说,我试图进行研究,但发现自己在所有争论中都有点迷失,为什么会出现潜在的僵局和其他问题。令我困惑的是所有的分歧。当然到2018年还有一种明确的方式吗?

谢谢,戴夫

P.S。对于那些关心的人,我正在玩SMC状态机库。请参阅:https://sourceforge.net/projects/smc/简而言之,状态机代码是从文本文件自动生成的。但生成的代码是同步方法。是的,我可以破解生成的代码(但它会被覆盖)或重新考虑整个问题(也许InitializeMachine应该不是asynch),但我的问题仍然存在。在我看来,有时同步方法需要调用异步方法,它们应该等到异步方法完成!

2 个答案:

答案 0 :(得分:2)

你应该使用这个:

InitializeMachine().GetAwaiter().GetResult();

这将确保InitializeMachine处引发的任何异常都不会包含在AggregateException中。请注意,由于您没有返回任何内容(return方法),因此不需要void语句。

修改
由于您使用的是WPF,如果您只保留异步 - 完全向下的模式会更好:

public async void InitializeMachineAsync()
{
    await DoSomeWork1().ConfigureAwait(false);
    await DoSomeWork2().ConfigureAwait(false);
}

InitializeMachineAsync可以是任何事件(例如Window_Load

答案 1 :(得分:-1)

最简单的事情是

InitializeMachine().Wait();

有一些关于异常处理的注意事项