非同期アクションデリゲートメソッドはどのように実装しますか?


132

少し背景情報。

私はWeb APIスタックを学び、SuccessやErrorCodesなどのパラメーターを持つ「Result」オブジェクトの形式ですべてのデータをカプセル化しようとしています。

ただし、メソッドが異なれば結果やエラーコードも異なりますが、結果オブジェクトは一般的に同じ方法でインスタンス化されます。

時間を節約し、C#の非同期/待機機能の詳細を学ぶために、Web APIアクションのすべてのメソッド本体を非同期アクションデリゲートでラップしようとしていますが、ちょっとした問題に巻き込まれています...

次のクラスがあるとします。

public class Result
{
    public bool Success { get; set; }
    public List<int> ErrorCodes{ get; set; }
}

public async Task<Result> GetResultAsync()
{
    return await DoSomethingAsync<Result>(result =>
    {
        // Do something here
        result.Success = true;

        if (SomethingIsTrue)
        {
            result.ErrorCodes.Add(404);
            result.Success = false;
        }
    }
}

Resultオブジェクトに対してアクションを実行してそれを返すメソッドを書きたいのですが。通常、同期メソッドを介して

public T DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    T result = new T();
    resultBody(result);
    return result;
}

しかし、このメソッドをasync / awaitを使用して非同期メソッドに変換するにはどうすればよいですか?

これは私が試したものです:

public async Task<T> DoSomethingAsync<T>(Action<T, Task> resultBody) 
    where T: Result, new()
{
    // But I don't know what do do from here.
    // What do I await?
}

1
を起動している場合、メソッドを非同期にする必要がnewあるのTはなぜですか?非同期API を使用するコードでAFAIK asyncを使用する場合は、使用する他のメソッドからネスネスを伝達するだけで済みます。
ミリムース2013

申し訳ありませんが、これはまだかなり新しいのですが、伝達するだけでよいと言うとき、どういう意味ですか。
Albin Anke

私はそれを理解したと思います、ミリムースが私に何か考えてくれたことを感謝します。
Albin Anke

1
なぜこれを非同期にしようとするのですか?多くの場合、Webサーバーの状況ではなく、同期コードをタスクでラップすることによって偽の非同期を実行すること(実行しようとしているように)は、同期的に実行するより低速です。
スコットチェンバレン

1
@AlbinAnke「伝播」とは、メソッドのように.NETメソッドを呼び出す場合Stream.ReadAsync()、そのメソッド自体が非同期であり、同期したメソッドであったTask<T>場所を返す場所を返すことを意味しますT。このようにすると、メソッドのすべての呼び出し元は、基になるメソッドがStream.ReadAsync()完了するまで「非同期に待機する」ことができます(これについて何がいいのかわかりません)。使用できるこれのメタファーは、非同期は「感染性」であり、低レベルの組み込みI / Oから、そのI / Oの結果に依存する結果を持つ他のコードに広がるということです。
millimoose 2013

回答:


307

asyncのと同等でAction<T>あるFunc<T, Task>私は、これはあなたが探しているものであると信じて、:

public async Task<T> DoSomethingAsync<T>(Func<T, Task> resultBody)
    where T : Result, new()
{
  T result = new T();
  await resultBody(result);
  return result;
}

@Stephen明らかに、私はMVVM ligth Messengerに同様のものを実装しようとしていますが、同じ方法で実装できますか?
ファンパブロゴメス

@JuanPabloGomez:私は彼らの種類のメッセージングに精通していませんが、なぜそれが機能しないのか分かりません。
Stephen Cleary 2015年

1
これは素晴らしいです!非同期アクションを作成することは不可能だと思っていましたが、すでに言語の欠陥だと考えていました。Funcの使用については考えていませんでした。ありがとう。
Noel Widmer 2018年

2
@DFSFOT:voidメソッドに相当する非同期メソッドはTask-returningメソッドです。したがって、非同期のActionis Func<Task>に相当し、非同期のis に相当しAction<T>ますFunc<T, Task>。詳細はこちら
Stephen Cleary

1
@DFSFOT:非同期メソッドTaskは、戻り値がない場合に戻る必要があります。asyncキーワードを使用する場合、実際のTaskインスタンスは関数ではなくステートマシンによって直接作成されます。
Stephen Cleary

-11

したがって、これを実装する方法は次のとおりです。

public Task<T> DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    return Task<T>.Factory.StartNew(() =>
    {
        T result = new T();
        resultBody(result);
        return result;
    });
}

7
ASP.NETでは回避する必要がありますTask.Run(さらに回避する必要StartNewがあります)。
Stephen Cleary

これを行うためのより良い方法は何ですか?
Albin Anke

私は回答を投稿し、@ svickの回答にも賛成しました。どちらも良い答えです。
Stephen Cleary
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.