web-dev-qa-db-ja.com

コールバックベースの非同期メソッドを待機可能なタスクに変換する最良の方法

(待機可能な)タスクを返すものへのコールバックを使用する「クラシック」非同期メソッドを変換/ラップする最良の方法は何でしょうか?

たとえば、次の方法を考えます:

public void GetStringFromUrl(string url, Action<string> onCompleted);

これをタスクを返すメソッドにラップする唯一の方法は次のとおりです。

public Task<string> GetStringFromUrl(string url)
{
     var t = new TaskCompletionSource<string>();

     GetStringFromUrl(url, s => t.TrySetResult(s));

     return t.Task;
}

これがこれを達成する唯一の方法ですか?

また、GetStringFromUrl(url、callback)への呼び出しをタスク自体にラップする方法があります(つまり、呼び出し自体は同期ではなくタスク内で実行されます)

63

あなたのコードは短く、読みやすく、効率的です。そのため、なぜ代替手段を探しているのか理解できませんが、何も考えられません。あなたのアプローチは合理的だと思います。

また、なぜ同期部分は元のバージョンでは問題ないと思うのかわかりませんが、Taskベースのものでは回避したいのです。同期部分に時間がかかりすぎると思われる場合は、メソッドの両方のバージョンで修正してください。

ただし、ThreadPoolバージョンでのみ非同期に(つまり、Taskで)実行する場合は、 Task.Run() を使用できます。

public Task<string> GetStringFromUrl(string url)
{
    return Task.Run(() =>
    {
        var t = new TaskCompletionSource<string>();

        GetStringFromUrl(url, s => t.TrySetResult(s));

        return t.Task;
    });
}
32
svick

コールバックが成功した状況のみを処理することを想定しているため、想定する実装はこれでまったく問題ありません。 GetStringFromUrl実装の非同期基盤内で例外が発生すると、現在何が起こりますか?彼らがそれをアクションコールバックに伝播する本当の方法はありません...彼らはそれを飲み込んでnullまたは何かを返しますか?

私がお勧めするのは、このような非同期メソッドにXXXAsyncサフィックスを付けるという新しい規則に従うことです。

3
Drew Marsh