我正在尝试将同步方法从一些旧代码转换为异步方法,但我理解有些麻烦。从我读过的所有视频和教程中,他们似乎都在创建方法,一个是实际的函数,另一个是包装器,然后是在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());
我是否需要一个也设置为异步的包装器方法来调用登录?
所有这些看起来有点复杂。
答案 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
关键字,这需要将其设为async
。 await
关键字基本上将方法划分为await
,将await
之后的部分转换为在等待Task
完成时继续的委托。该方法在遇到await
后立即返回。
您的登录功能不使用await
。它不需要async
关键字。