web-dev-qa-db-ja.com

インターフェースと非同期の設計

私がそのようなメソッドでインターフェースIFolderRepositoryを作成したとしましょう:

IEnumerable<Folder> GetAllFolders();
Folder GetFolderWithId(int id);
void AddFolder(Folder newFolder);
void ModifyFolder(Folder folderToModify, Folder folderAfterModification);
void RemoveFolder(Folder folderToRemove);

DatabaseFolderRepositoryを実装し、CacheFolderRepositoryDecoratorと言いましょう。ここで「数百行後」にSkyDriveフォルダーの機能を追加したいので、SkyDriveFolderRepositoryを追加します。残念ながら、DatabaseFolderRepositoryの実装ではデータベースと通信するために同期メソッドを使用していましたが、skydrive 1では多くのasyncawaitを使用しています。そのような場合はどうしますか? voidメソッドで非同期とマークされている場合は、解決策ではありません(例外処理が必要)。 Task<T>を返すようにインターフェイスを変更する必要がありますか?確かに上記の例では機能しますが、これらは2つのインターフェース実装クラスにすぎません。それとも、ほとんどのインターフェイスにTask戻り値の型を指定する必要がありますか(ルールが不要になるのに対して)。

9
fex

おそらく、このMSDNの記事 非同期のプラクティス を読むとよいでしょう。

あなたは尋ねました:

残念ながら、DatabaseFolderRepositoryの実装ではデータベースと通信するために同期メソッドを使用していましたが、skydrive 1では多くのasyncawaitを使用しています。

これは、サブセクションAsync All the Way私がリンクしたMSDN記事の中で、あなたの状況に関連しているでしょう。

特に、通常、非同期コードでTask.WaitまたはTask.Resultを呼び出してブロックすることはお勧めできません。これは、アプリケーションのごく一部を変換し、それを同期APIでラップしてアプリケーションの残りの部分を変更から切り離す、非同期プログラミングに「足を踏み入れ」ているプログラマーにとって特に一般的な問題です。残念ながら、それらはデッドロックの問題に遭遇します。

非同期にする必要があるインターフェースが少なくとも1つあるため、YAGNIは逆になります。あなたインターフェースを一貫させるために変更を加える必要があります。はい、それはあなたのために前により多くの努力を作成します。しかし、利点はデッドロックのリスクが少ないことです。それほど複雑でないデバッグ。さらに予測可能なブロッキング(実際に発生する必要がある場合)。

私はあなたの質問の核心に対処したと思うので、あなたが尋ねた他のいくつかの質問をスキップしています。コアに対処すれば、残りの質問は失敗します。この記事はかなり複雑で、あなたが提起した他のポイントに対処するだけでなく、追加の落とし穴を指摘しています。

非同期プログラミングは、コンセプト全体を受け入れて、それをそのまま使用しなければならないものの1つです。少しずつ「つま先をひっくり返す」ことを試みると、まっすぐにジャンプするよりもはるかに複雑になります。

10
user53019