ConfigureAwait(false)
C# で await/async を使用する場合、 をいつ使用するかについては、多くのガイドラインがあります。
ConfigureAwait(false)
同期コンテキストに依存することはめったにないため、ライブラリコードで使用することが一般的に推奨されているようです。
ただし、関数を入力として受け取る非常に一般的なユーティリティ コードを作成しているとします。簡単な例としては、単純なタスクベースの操作を簡単にするための次の (不完全な) 関数コンビネータがあります。
地図:
public static async Task<TResult> Map<T, TResult>(this Task<T> task, Func<T, TResult> mapping)
{
return mapping(await task);
}
フラットマップ:
public static async Task<TResult> FlatMap<T, TResult>(this Task<T> task, Func<T, Task<TResult>> mapping)
{
return await mapping(await task);
}
問題は、ConfigureAwait(false)
この場合に使用する必要があるかどうかです。コンテキストキャプチャがどのように機能するかわかりません。閉鎖。
一方では、コンビネータが機能的な方法で使用される場合、同期コンテキストは必要ありません。一方、人々は API を誤用し、提供された関数でコンテキスト依存のことを行う可能性があります。
1 つのオプションは、各シナリオ (Map
およびMapWithContextCapture
または何か) ごとに個別のメソッドを用意することですが、見苦しく感じます。
別のオプションは、マップ/フラットマップからおよびへのオプションを追加することかもしれませんConfiguredTaskAwaitable<T>
が、awaitables はインターフェイスを実装する必要がないため、多くの冗長なコードが発生し、私の意見ではさらに悪化します。
実装されたライブラリが提供されたマッピング関数でコンテキストが必要かどうかについて仮定をする必要がないように、責任を呼び出し元に切り替える良い方法はありますか?
それとも、さまざまな仮定がないと、非同期メソッドがうまく構成されないというのは単なる事実ですか?
編集
いくつかのことを明確にするために:
- 問題は存在します。ユーティリティ関数内で「コールバック」を実行すると、 を追加
ConfigureAwait(false)
すると null 同期が発生します。環境。 - 主な問題は、この状況にどのように取り組むべきかということです。誰かが同期を使用する可能性があるという事実を無視する必要があります. または、オーバーロードやフラグなどを追加する以外に、責任を呼び出し元に移す良い方法はありますか?
いくつかの回答が言及しているように、メソッドにbool-flagを追加することは可能ですが、私が見るように、APIを介して伝播する必要があるため、これもあまりきれいではありません(上記のものに応じて、より多くの「ユーティリティ」機能)。