2

去年,我用经典的同步和异步方法编写了一个 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;
    }
}

现在它可以工作了。有人可以解释为什么第一个代码不起作用吗?

4

1 回答 1

4

您正在创建任务,但从未启动它。它是“冷”创建的 - 在实际调用提供给构造函数的函数之前,它需要一些东西来启动它。

要么 call Task.Start(),要么使用TaskEx.Run()orTask.Factory.StartNew()而不是调用Task构造函数:

public Task<string> AuthenticateTaskAsync(string username, string password) {
    return TaskEx.Run(() => this.Authenticate(username, password));
}

请注意,这里不需要匿名类型 - 只需让编译器捕获参数即可。

于 2012-02-13T13:17:44.193 回答