このシグネチャを持つポータブルクラスライブラリ内に非同期メソッドがあります。
private async Task<T> _Fetch<T>(Uri uri)
具体的な型Tとしてキャストバックされるリソースをフェッチします。
私は、パラメータの1つとしてFunc<T>
を必要とするサードパーティのキャッシュライブラリ( Akavache )を使用しており、次のようにしてみました。
await this.CacheProvider.GetOrCreateObject<T>(key,
async () => await _Fetch<T>(uri), cacheExpiry);
これはエラーになります:
非同期ラムダ式をデリゲート型 '
System.Func<T>
'に変換できません。非同期ラムダ式はvoid
、Task
またはTask<T>
を返す場合がありますが、いずれも「System.Func<T>
」に変換できません。
私はFunc<T>
割り当てのさまざまな組み合わせを試しましたが、コードを機能させる唯一の方法はFunc<T>
をブロックすることです。
await this.CacheProvider.GetOrCreateObject<T>(key,
() => _Fetch<T>(uri).Result, cacheExpiry);
これは私のアプリをデッドロックさせます。
私が迷うところへのポインタはありますか?
できません。誰かが_Func<T> f
_を期待している場合、result = f()
のようなもので呼び出されると想定できます。つまり、非同期の動作については知りません。あなたが持っているように_.Result
_を使用してそれをだます場合-UIスレッドでawait
(_Fetch内)の後にコードをスケジュールする必要があるため、UIスレッドでデッドロックしますが、すでにブロックしています_.Result
_を使用します。
非同期ラムダは、戻り値がないためAction
に、または_Func<Task>
_または_Func<Task<T>>
_に渡すことができます。
あなたのケースを見ると、GetOrCreateObject
がGetOrFetchObject
を呼び出しているようです。 GetOrFetchObject
オーバーロードの1つが_Func<Task<T>>
_を受け入れます。そのメソッドを非同期ラムダで呼び出して、それが役立つかどうかを確認できます。
YK1の回答 は、Func<T>
を非同期として処理できない理由を説明しています。
問題を解決するには、GetOrFetchObject
ではなくGetOrCreateObject
を使用してください。 「作成」メソッドは(同期)作成を前提としていますが、「フェッチ」メソッドは(非同期)検索で機能します。
await CacheProvider.GetOrFetchObject<T>(key, () => _Fetch<T>(uri), cacheExpiry)
また、ラムダ式から不要なasync
/await
を削除しました。 _Fetch
はすでにTask<T>
を返すため、そのタスクをasync
することのみを目的としたawait
ラムダを作成する必要はありません。