2

昨年、私は従来の同期メソッドと非同期メソッドを備えた Web API ライブラリを作成しました。新しいC# Async CTP 3を使用して TaskAsync メソッドを追加しようとしています。

sync メソッドをカプセル化するために、次の簡単なコードを書きました。

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

タスクを作成していますが、開始していません。「コールド」で作成されます-コンストラクターに提供された関数が実際に呼び出される前に、何かを開始する必要があります。

を呼び出すか、コンストラクタを呼び出す代わりにorTask.Start()を使用します。TaskEx.Run()Task.Factory.StartNew()Task

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

ここでは匿名型は必要ないことに注意してください。コンパイラにパラメータをキャプチャさせるだけです。

于 2012-02-13T13:17:44.193 に答える