我正在尝试将同步方法从一些旧代码转换为异步方法,但我有一些麻烦。从我读过的所有视频和教程中,他们似乎都在创建方法,一个是实际的函数,另一个是包装器,然后是在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());
我是否需要一个也设置为async的包装器方法来调用登录?
所有这些看起来有点复杂。
要先回答你的第二部分,是的,你需要为按钮标记事件 async
,如果你想使用关键字 await
在您的代码中,您必须声明该函数 async
。
如果功能使用,则为2 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;
}
在我的“重写方法”中,我正在做的是我正在使用 ExecuteAsync
女巫是 IRestClient的一部分。在我调用的回调方法中,该函数在完成时调用回调方法 tcs
的 SetResult
报告我想要的结果。
您可以通过参加进一步扩展这一点 CancellationToken
如果令牌被提出呼叫 Abort()
上 RestRequestAsyncHandle
但是,如果我们这样做,我们需要带来 async
返回到函数并等待结果,以便我们可以在取消令牌注册后进行清理。
private Task<bool> login(String username, String password)
{
return login(username, password, CancellationToken.None);
}
private async Task<bool> login(String username, String password, CancellationToken cancelToken)
{
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);
var asyncHandle = client.ExecuteAsync(request, (response, handle) =>
{
try
{
// Return loggin status
var dom = response.Content;
tcs.TrySetResult(dom["html"].HasClass("logged-in"));
}
catch(Exception ex)
{
tcs.TrySetException(ex);
}
});
//if the token is canceled it will call `asyncHandle.Abort()` for us.
using(cancelToken.Register(() =>
{
if(tcs.TrySetCanceled(cancelToken))
asyncHandle.Abort();
}))
{
return await tcs.Task;
}
}
要先回答你的第二部分,是的,你需要为按钮标记事件 async
,如果你想使用关键字 await
在您的代码中,您必须声明该函数 async
。
如果功能使用,则为2 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;
}
在我的“重写方法”中,我正在做的是我正在使用 ExecuteAsync
女巫是 IRestClient的一部分。在我调用的回调方法中,该函数在完成时调用回调方法 tcs
的 SetResult
报告我想要的结果。
您可以通过参加进一步扩展这一点 CancellationToken
如果令牌被提出呼叫 Abort()
上 RestRequestAsyncHandle
但是,如果我们这样做,我们需要带来 async
返回到函数并等待结果,以便我们可以在取消令牌注册后进行清理。
private Task<bool> login(String username, String password)
{
return login(username, password, CancellationToken.None);
}
private async Task<bool> login(String username, String password, CancellationToken cancelToken)
{
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);
var asyncHandle = client.ExecuteAsync(request, (response, handle) =>
{
try
{
// Return loggin status
var dom = response.Content;
tcs.TrySetResult(dom["html"].HasClass("logged-in"));
}
catch(Exception ex)
{
tcs.TrySetException(ex);
}
});
//if the token is canceled it will call `asyncHandle.Abort()` for us.
using(cancelToken.Register(() =>
{
if(tcs.TrySetCanceled(cancelToken))
asyncHandle.Abort();
}))
{
return await tcs.Task;
}
}
您的按钮处理程序使用 await
关键字,需要制作它 async
。该 await
关键字基本上分区方法 await
,转过身后的部分 await
成为一个在等待时继续的代表 Task
完成。该方法遇到后立即返回 await
。
您的登录功能不使用 await
。它不需要 async
关键词。