我有一个async方法:

public async Task<string> GenerateCodeAsync()
{
    string code = await GenerateCodeService.GenerateCodeAsync();
    return code;
}

我需要从一个同步方法调用这个方法。

我如何才能做到这一点,而不必复制GenerateCodeAsync方法,以使其同步工作?

更新

但没有找到合理的解决方案。

但是,我看到HttpClient已经实现了这个模式

using (HttpClient client = new HttpClient())
{
    // async
    HttpResponseMessage responseAsync = await client.GetAsync(url);

    // sync
    HttpResponseMessage responseSync = client.GetAsync(url).Result;
}

当前回答

如果你有一个名为“RefreshList”的异步方法,那么你可以从一个非异步方法调用该异步方法,如下所示。

Task.Run(async () => { await RefreshList(); });

其他回答

你可以访问任务的Result属性,这将导致你的线程阻塞,直到结果可用:

string code = GenerateCodeAsync().Result;

注意:在某些情况下,这可能会导致死锁:对Result的调用阻塞主线程,从而阻止异步代码的其余部分执行。你有以下选项来确保这种情况不会发生:

添加.ConfigureAwait(false)到你的库方法或 显式地在线程池线程中执行async方法,并等待它完成: string code = Task.Run(() => GenerateCodeAsync).Result;

这并不意味着你应该在所有异步调用之后盲目地添加.ConfigureAwait(false) !有关为什么以及何时应该使用.ConfigureAwait(false)的详细分析,请参阅以下博客文章:

.NET博客:ConfigureAwait FAQ

为了防止死锁,当我必须同步调用@Heinzi提到的异步方法时,我总是尝试使用Task.Run()。

但是,如果异步方法使用参数,则必须修改该方法。例如Task.Run(GenerateCodeAsync("test"))。结果给出了错误:

参数1:不能从'System.Threading.Tasks.Task<string>'转换 的系统。行动”

它可以被这样调用:

string code = Task.Run(() => GenerateCodeAsync("test")).Result;

这个线程上的大多数答案要么很复杂,要么会导致死锁。

下面的方法很简单,它将避免死锁,因为我们正在等待任务完成,然后才得到它的结果-

var task = Task.Run(() => GenerateCodeAsync()); 
task.Wait();
string code = task.Result;

此外,这里有一篇引用MSDN的文章,讨论了完全相同的事情- https://blogs.msdn.microsoft.com/jpsanders/2017/08/28/asp-net-do-not-use-task-result-in-main-context/

编辑:

Task有一个Wait方法Task.Wait(),它等待“promise”解析,然后继续执行,从而将其呈现为同步的。 例子:


async Task<String> MyAsyncMethod() { ... }

String mySyncMethod() {

    return MyAsyncMethod().Wait();
}

您可以使用同步方法生成器库(nuget)来生成此代码的同步版本。

使用方法如下:

[Zomp.SyncMethodGenerator.CreateSyncVersion]
public async Task<string> GenerateCodeAsync()
{
    string code = await GenerateCodeService.GenerateCodeAsync();
    return code;
}

它会生成GenerateCode方法,你可以同步调用。

将要生成的源是:

public string GenerateCode()
{
    string code = GenerateCodeService.GenerateCode();
    return code;
}