9

編集(承認後)

すぐにはわからないかもしれませんが、@ Servyの答えは、Unwrapunder monodroidのカスタム実装を必要とせずに正しいです-私のコメントでは、存在しないと言いましたが、確かに存在します。

編集を終了

私はRESTfulWebサービスを使用するアプリをたくさん書いていますが、タスクを適切に使用する方法を知っていると思っていても、そうではないことがわかりました。シナリオは、Windowsストア用に実装されたコードを持っているということです-を使用してasync/await、MonoDroidとほぼ同じものを実装する必要があります-それはありません(使用したくないビルドハックがない場合)。

この質問の問題を、整数を非同期で取得するための単純な一連のタスクに要約しました。次に、続けて、その整数から構築された文字列を変換する別の非同期タスクを起動します。C#5では、これは次のようになります。

注-もちろんTask.FromResult<T>、実際の非同期コードの代わりにここで使用しています

private async Task<string> GetStringAsync()
{
    return await GetStringFromIntAsync(await GetIntAsync());
}

private async Task<int> GetIntAsync()
{
    return await Task.FromResult(10);
}

private async Task<string> GetStringFromIntAsync(int value)
{
    return await Task.FromResult(value.ToString());
}

これを継続ベースのパターンに変換するために、私はこれを試しました:

private Task<string> GetStringAsync()
{
    //error on this line
    return GetIntAsync().ContinueWith(t => GetStringFromIntAsync(t.Result));
}

private Task<int> GetIntAsync()
{
    return Task.FromResult(10);
}

private Task<string> GetStringFromIntAsync(int value)
{
    return Task.FromResult(value.ToString());
}

ただし、このメソッドは、継続が.の代わりにを返すことになるという意味をGetStringFromIntAsync返すため、これは正しくありません。Task<string>Task<Task<string>>Task<string>

GetStringFromIntAsyncただし、メソッドを明示的に待機することは機能することがわかりました。

private Task<string> GetStringAsync()
{
    return GetIntAsync().ContinueWith(t =>
    {
        var nested = GetStringFromIntAsync(t.Result);
        nested.Wait();
        return nested.Result;
    });
}

問題は、しかし、それを行う正しい方法であるということですが、呼び出し元が待機するある種の継続を返すことはできませんか?

私はタスクをかなり使用しましたが、このように異なるタイプのタスクを連鎖させることはしませんでした(もちろんasync/awaitを除く)。そして、ここで怒っているように感じます。助けていただければ幸いです。

4

3 に答える 3

5

したがって、最初に、2番目と3番目の実装の非非同期/待機の実装は、非同期/待機がある場合でも実行する必要があります。これを使用すると、不要なオーバーヘッドが少し増える以外は何も追加されません。

最初のケースに関しては、いいえ、使用したくありませんWait。これにより、スレッドをプールに戻すのではなく、ブロックします。タスクをアンラップして、その内部タスクを取得するだけです。Unwrapこのメソッドを使用して、次のことを行うことができます。

private Task<string> GetStringAsync()
{
    return GetIntAsync()
        .ContinueWith(t => GetStringFromIntAsync(t.Result))
        .Unwrap();
}

Unwrap利用できない場合に使用できる機能は次のとおりです。

public static Task<T> Unwrap<T>(this Task<Task<T>> task)
{
    var tcs = new TaskCompletionSource<T>();

    task.ContinueWith(t =>
    {
        t.Result.ContinueWith(innerT => tcs.SetResult(innerT.Result)
            , TaskContinuationOptions.OnlyOnRanToCompletion);
        t.Result.ContinueWith(innerT => tcs.SetCanceled()
            , TaskContinuationOptions.OnlyOnCanceled);
        t.Result.ContinueWith(innerT => tcs.SetException(innerT.Exception.InnerExceptions)
            , TaskContinuationOptions.OnlyOnRanToCompletion);
    }
        , TaskContinuationOptions.OnlyOnRanToCompletion);
    task.ContinueWith(t => tcs.SetCanceled()
        , TaskContinuationOptions.OnlyOnCanceled);
    task.ContinueWith(t => tcs.SetException(t.Exception.InnerExceptions)
        , TaskContinuationOptions.OnlyOnFaulted);

    return tcs.Task;
}
于 2013-01-18T16:07:48.437 に答える
0

完全にサポートされたアプローチについては、MonoDroidの公式の非同期/待機サポートを待つのがおそらく最善です-Xamarinはこれが「間もなく登場する」と言っています-今年の前半。

ただし、もっと冒険的な気分になっている場合は、少なくとも2人の人がMonoDroidで非同期/待機することができます。

于 2013-01-19T12:18:00.990 に答える
-1

これは、.net 4.0(VS 2010)で非同期タスクを操作して行ったことです。電話をかける必要はないと言う人もいれば、電話をかける必要があると言う人もいtask.Wait();ますtask.Wait();。違いは、task.Wait()がtask.Resultプロパティに暗黙的に含まれているかカプセル化されているかどうかです。

私はを呼び出すというより明確なアプローチに固執しましたtask.Wait();

これは通話が完了するまでブロックされますが、4.5を使用していない場合、他にどのようなオプションが利用できるかわかりません。

于 2013-01-18T16:10:25.937 に答える