3

基本的に他のメソッドをラップする便利なメソッドを持つコードを書くことがよくあります。簡単な例を次に示します。

public class WithoutAsync
{
    public static ReadOnlyCollection<Response> GetResponses(IEnumerable<Request> fromRequests)
    {
        var ret = new List<Response>();

        foreach (Request r in fromRequests)
        {
            ret.Add(new Response());
        }

        return ret.AsReadOnly();
    }

    //convenience method
    public static Response GetResponse(Request fromRequest)
    {
        return GetResponses(new Request[] {fromRequest})[0];
    }
}

今、私はawait長時間実行する操作をしたいのですが、この方法論を TPL で使用するために改造する方法がよくわかりません。

public class WithAsync
{
    public static async Task<ReadOnlyCollection<Response>> GetResponses(IEnumerable<Request> fromRequests)
    {
        var awaitableResponses = new List<Task<Response>>();

        foreach (Request r in fromRequests)
        {
            awaitableResponses.Add(Task.Run<Response>(async () =>
                {
                    await Task.Delay(10000); //simulate some long running async op.
                    return new Response();
                }));
        }

        return new List<Response>(await Task.WhenAll(awaitableResponses)).AsReadOnly();
    }

    //convenience method
    public static Task<Response> GetResponse(Request fromRequest)
    {
        return GetResponse(new Request[] { fromRequest });
    }
}

Task<ReadOnlyCollection<Response>>上記の便利なメソッドは、本当に a を返す必要があるときに a を返そうとしているため、明らかに機能しませんTask<Response>

これは機能します:

//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
    return new Task<Response>(new Func<Response>(() => GetResponse(new Request[] { fromRequest }).Result[0]));
}

しかし、それは本当にぎこちなく見えます。さらに重要なこと.Result[0]に、UI スレッド上にある可能性のあるものをブロックします。

私がやろうとしていることを達成する良い方法はありますか?

4

2 に答える 2

5

その「便利な方法」を避けようとしていますがasync、そうする理由はありません。

あなたが望むのは、他のメソッドを呼び出し、応答があるまで待ってから、最初で唯一のメソッドを取得することです。asyncそれを作成して使用することでそれを行うことができますawait

async Task<Response> GetResponseAsync(Request fromRequest)
{
    var responses = await GetResponsesAsync(new[] { fromRequest });
    return responses.Single();
}

この特定のケースでのより良い解決策は、物事を切り替えてGetResponse、単一の要求のその作業を実際に実行し、GetRsponses代わりに複数の呼び出しを行うことです。

async Task<ReadOnlyCollection<Response>> GetResponsesAsync(IEnumerable<Request> fromRequests)
{
    return (await Task.WhenAll(fromRequests.Select(GetResponse))).ToList().AsReadOnly();
}

async Task<Response> GetResponseAsync(Request fromRequest)
{
    await Task.Delay(10000); //simulate some long running async op.
    return new Response();
}

ノート:

  • 例であることはわかっていますが、単純な呼び出しTask.Runの代わりに使用する理由はおそらくないでしょう。async
  • 規則ではasync、「Async」接尾辞 (つまりGetResponseAsync) を付けてメソッドに名前を付けます。
  • コレクションを返すメソッドの名前も複数形にしました。
于 2015-01-30T20:38:30.597 に答える
0

よく書かれた有益な回答なので、私はまだI3arnonの回答に固執していますが、ほとんどそこにいることに気付いたので、自分の回答を提出したいと思います。asyncこれが私が見つけるのに苦労していた便利な方法です:

//convenience method
public static async Task<Response> GetResponse(Request fromRequest)
{
    return (await GetResponses(new Request[] { fromRequest }))[0];
}
于 2015-01-30T21:48:37.023 に答える