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

当前回答

编辑:

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


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

String mySyncMethod() {

    return MyAsyncMethod().Wait();
}

其他回答

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

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

您可以使用同步方法生成器库(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;
}

你应该可以用委托,lambda表达式来完成

private void button2_Click(object sender, EventArgs e)
    {

        label1.Text = "waiting....";

        Task<string> sCode = Task.Run(async () =>
        {
            string msg =await GenerateCodeAsync();
            return msg;
        });

        label1.Text += sCode.Result;

    }

    private Task<string> GenerateCodeAsync()
    {
        return Task.Run<string>(() => GenerateCode());
    }

    private string GenerateCode()
    {
        Thread.Sleep(2000);
        return "I m back" ;
    }

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

这可以通过GenerateCodeAsync()实现。Result或GenerateCodeAsync(). wait(),如其他答案所示。这将阻塞当前线程,直到GenerateCodeAsync完成。

然而,你的问题被标记为asp.net,你也留下了评论:

我希望有一个更简单的解决方案,认为asp.net可以处理 这比写这么多行代码要容易得多

我的观点是,你不应该阻塞ASP.NET中的异步方法。这将降低web应用的可伸缩性,并且可能会产生死锁(当GenerateCodeAsync内部的await continuation被发布到AspNetSynchronizationContext时)。使用Task.Run(……)。结果,将某些内容卸载到池线程,然后阻塞将进一步损害可伸缩性,因为它会导致+1个线程来处理给定的HTTP请求。

ASP。NET内置了对异步方法的支持,可以通过异步控制器(在ASP。NET MVC和Web API)或直接通过经典ASP.NET中的AsyncManager和PageAsyncTask。你应该使用它。要了解更多细节,请检查这个答案。

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

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

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

它可以被这样调用:

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