我正在尝试将同步方法从一些旧代码转换为异步方法,但我有一些麻烦

时间:2013-08-10 21:23:20

标签: c# async-await

我正在尝试将同步方法从一些旧代码转换为异步方法,但我理解有些麻烦。从我读过的所有视频和教程中,他们似乎都在创建方法,一个是实际的函数,另一个是包装器,然后是在UI上调用的包装器。

这是我的代码:

private async Task<bool> login(String username, String password)
{
        var tcs = new TaskCompletionSource<RestSharp.IRestResponse>();

        RestSharp.RestRequest request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.GET);
        RestSharp.IRestResponse response = client.Execute(request);

        // Make the login request
        request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.POST);
        request.AddParameter("username", username);
        request.AddParameter("password", password);

        response = client.Execute(request);

        // Return loggin status
        dom = response.Content;
        return dom["html"].HasClass("logged-in"); 
}

出于某种原因,当我尝试通过点击按钮调用UI线程上的方法时,它要求我将按钮事件设置为异步。

txtLog.AppendText("Before Await");

Task<bool> result = await login("","");

txtLog.AppendText("After Await");
txtLog.AppendText("Result: " + result.toString());

我是否需要一个也设置为异步的包装器方法来调用登录?

所有这些看起来有点复杂。

2 个答案:

答案 0 :(得分:13)

首先回答您的第二部分,是的,您需要为按钮async标记事件,如果您想在代码中使用关键字await,则必须声明函数{{1} }。

如果函数使用async但其中没有async,则代码将不会异步运行,您需要创建一个任务并在其中运行同步方法或重写方法是异步的。

作为任务方法:

await

重写函数方法:

private async void button1_Click(object sender, EventArgs e)
{
    txtLog.AppendText("Before Await");

    //Note I changed from "Task<bool>" to "bool", await is like calling ".Result" 
    //  on a task but not blocking the UI, so you store the type you are waiting for.
    bool result = await Task.Run(() => login("","")); //You would still use your old login code before you tried to make it async, it requires no modifications.

    txtLog.AppendText("After Await");
    txtLog.AppendText("Result: " + result.ToString());
}

在我的“重写方法”中,我正在使用的是private async void button1_Click(object sender, EventArgs e) { txtLog.AppendText("Before Await"); //Note I changed from "Task<bool>" to "bool", await is like calling ".Result" // on a task but not blocking the UI, so you store the type you are waiting for. bool result = await login("",""); txtLog.AppendText("After Await"); txtLog.AppendText("Result: " + result.ToString()); } private Task<bool> login(String username, String password) { var tcs = new TaskCompletionSource<bool>(); // Make the login request var request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.POST); request.AddParameter("username", username); request.AddParameter("password", password); client.ExecuteAsync(request, (response, handle) => { try { // Return loggin status var dom = response.Content; //dom["html"] did not have a .HasClass in my tests, so this code may need work. tcs.TrySetResult(dom["html"].HasClass("logged-in")); } catch(Exception ex) { tcs.TrySetException(ex); } }); return tcs.Task; } 女巫part of IRestClient。该函数在完成后调用回调方法,在回调方法中,我调用ExecuteAsync的{​​{1}}来报告我想要的结果。

你可以通过tcs进一步扩展这一点,如果提出了令牌,请SetResult上的CancellationToken,但是如果我们这样做,我们需要带Abort()返回函数并等待结果,以便我们可以在取消令牌注册后进行清理。

RestRequestAsyncHandle

答案 1 :(得分:1)

您的按钮处理程序使用await关键字,这需要将其设为asyncawait关键字基本上将方法划分为await,将await之后的部分转换为在等待Task完成时继续的委托。该方法在遇到await后立即返回。

您的登录功能不使用await。它不需要async关键字。