我有一个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;
}

当前回答

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

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

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

它可以被这样调用:

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

其他回答

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

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

我更喜欢非阻塞的方法:

            Dim aw1=GenerateCodeAsync().GetAwaiter()
            While Not aw1.IsCompleted
                Application.DoEvents()
            End While

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

string code = GenerateCodeAsync().Result;

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

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

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

.NET博客:ConfigureAwait FAQ

您应该获取一个等待器(GetAwaiter()),并结束异步任务完成的等待(GetResult())。

string code = GenerateCodeAsync().GetAwaiter().GetResult();

Microsoft Identity具有同步调用异步方法的扩展方法。 例如,有GenerateUserIdentityAsync()方法和CreateIdentity()方法

如果你查看UserManagerExtensions.CreateIdentity() 它是这样的:

 public static ClaimsIdentity CreateIdentity<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user,
        string authenticationType)
        where TKey : IEquatable<TKey>
        where TUser : class, IUser<TKey>
    {
        if (manager == null)
        {
            throw new ArgumentNullException("manager");
        }
        return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType));
    }

现在让我们看看AsyncHelper。RunSync确实

  public static TResult RunSync<TResult>(Func<Task<TResult>> func)
    {
        var cultureUi = CultureInfo.CurrentUICulture;
        var culture = CultureInfo.CurrentCulture;
        return _myTaskFactory.StartNew(() =>
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = cultureUi;
            return func();
        }).Unwrap().GetAwaiter().GetResult();
    }

这是async方法的包装器。 请不要从Result中读取数据——它可能会在ASP中阻塞你的代码。

还有另一种方法——对我来说有点可疑,但你也可以考虑一下

  Result r = null;

            YourAsyncMethod()
                .ContinueWith(t =>
                {
                    r = t.Result;
                })
                .Wait();