去年,我使用经典的同步和异步方法编写了一个Web API库。我现在正尝试使用新的 C#Async CTP 3 添加TaskAsync方法。
我编写了这个简单的代码来封装同步方法:
partial class Client : IClient {
public string Authenticate(string username, string password)
{
// long synchronous code here
}
public Task<string> AuthenticateTaskAsync(string username, string password) {
var p = new { username = username, password = password };
var task = new Task<string>(p1 => this.Authenticate(p.username, p.password), p);
return task;
}
}
然后,从我的WPF 4应用程序中,我有一个使用它的异步方法:
public class LoginViewModel {
private IClient client;
// called by an ICommand
private async Task DoLogin(string username, string password) {
UpdateStatus("Authenticating...", true);
try {
var result = await client.AuthenticateTaskAsync(username, password);
// do stuff with result
UpdateStatus("Authenticated. Fetching User informations...", true);
} catch (Exception ex) {
UpdateStatus("Authentication error.", ex, false);
}
}
}
问题是:我的同步方法永远不会被调用。调试器转到result = await client.AuthenticateTaskAsync(username, password);
,调试器继续工作,永远不会回来。同步Authenticate
内的断点断开。 UpdateStatus
永远不会被调用。很奇怪(我虽然这是一个调试器实现问题)。
然后我看了WebClient.DownloadStringTaskAsync
是如何实现的。我将我的API客户端方法更改为:
partial class Client : IClient {
public Task<string> AuthenticateTaskAsync(string username, string password) {
var tcs = new TaskCompletionSource<string>();
try {
tcs.TrySetResult(this.Authenticate(username, password));
} catch (Exception ex) {
tcs.TrySetException(ex);
}
return tcs.Task;
}
}
现在它有效。有人可以解释为什么第一个代码不起作用吗?
答案 0 :(得分:4)
您正在创建任务但从未启动它。它被创建为“冷” - 在实际调用提供给构造函数的函数之前需要启动它。
请致电Task.Start()
,或使用TaskEx.Run()
或Task.Factory.StartNew()
代替调用Task
构造函数:
public Task<string> AuthenticateTaskAsync(string username, string password) {
return TaskEx.Run(() => this.Authenticate(username, password));
}
请注意,此处不需要匿名类型 - 只需让编译器捕获参数。