【C#】async/awaitで同期メソッドから非同期メソッドを呼ぶ方法

表題のとおり、同期メソッドから非同期メソッドの呼びだし方が
わからない人向けの記事になります。

エラー CS4033 await’ 演算子は、非同期メソッド内でのみ使用できます。
このメソッドに ‘async’ 修飾子を指定し、
戻り値の型を ‘Task’ に変更することを検討してください。

私も、同期メソッドから非同期メソッドをうまく呼び出せず、
このようなエラーを経験しました。

そのときの対応でうまくいった方法を紹介したいと思います。

awaitを使わないことで同期と非同期をつなぐ

いきなりですが解決策の同期メソッドから非同期メソッドを呼ぶコードです。


ポイントは「Task.Run」を使うこと、

「await」を使わずに「.GetAwaiter().GetResult()」を使うことです。

visual studioでコーディングしていると冒頭のメッセージ

エラー CS4033 await’ 演算子は、非同期メソッド内でのみ使用できます。
このメソッドに ‘async’ 修飾子を指定し、
戻り値の型を ‘Task’ に変更することを検討してください。

が発生します。

「非同期のasyncメソッドを呼ぶときはawaitを使用する」ことが
奨励されていますので、それを提案している内容ですね。

しかし、提案内容をそのまま採用してしまうと

asyncを呼び出す箇所にawaitをいれて
awaitを使うために呼び出し元にasyncを入れて
さらにasyncを呼び出す箇所にawaitを・・・

と、マトリョーシカのごとくasyncメソッドを作り続けることになります。

しかし、同期メソッドにawaitを使えないことは変わりませんので、
「.GetAwaiter().GetResult()」を代わりに使用します。

昔のバージョンのC#ではMain()にawaitが使えない

昔のバージョンのC#では、「Main()」にasync/awaitが使えませんでした。

最新のC#であればMain()を非同期にできます。


そのため、古いバージョンのC#を使用する場合、
「.GetAwaiter().GetResult()」が必要になります。

もし、古いバージョンのアプリで非同期を実行する場合は、
Mainメソッドで同期メソッドを呼び出したほうがよいです。


経験上、同期メソッドと非同期メソッドが混ざる箇所が減り、
デッドロックで落ちるコードが紛れにくくなります。

まとめ

  • 同期メソッドで Task.Run() を使用する
  • 同期メソッドで .GetAwaiter().GetResult() を使用する

以上がC#で同期メソッドから非同期メソッドを呼ぶ方法になります。

一度非同期メソッドにしてしまえばそれ以降も非同期になりますので、
リソースを効率よく使うことができます。

非同期メソッドを使用したいというときに、
是非、利用してみてください。