次の方法で共有


オブザーバー デザイン パターンのベスト プラクティス

.NET では、オブザーバー デザイン パターンはインターフェイスのセットとして実装されます。 System.IObservable<T> インターフェイスはデータ プロバイダーを表します。これは、オブザーバーが通知のサブスクライブを解除できるようにするIDisposable実装を提供する役割も担います。 System.IObserver<T> インターフェイスはオブザーバーを表します。 このトピックでは、これらのインターフェイスを使用してオブザーバー デザイン パターンを実装するときに開発者が従う必要があるベスト プラクティスについて説明します。

スレッド

通常、プロバイダーは、コレクション オブジェクトによって表されるサブスクライバー リストに特定のオブザーバーを追加することによって、 IObservable<T>.Subscribe メソッドを実装し、サブスクライバー リストから特定のオブザーバーを削除することによって IDisposable.Dispose メソッドを実装します。 オブザーバーは、いつでもこれらのメソッドを呼び出すことができます。 さらに、プロバイダー/オブザーバー コントラクトでは、 IObserver<T>.OnCompleted コールバック メソッドの後にサブスクライブ解除を担当するユーザーが指定されていないため、プロバイダーとオブザーバーの両方がリストから同じメンバーを削除しようとする可能性があります。 このような可能性があるため、 Subscribe メソッドと Dispose メソッドの両方がスレッド セーフである必要があります。 通常、これには 同時実行コレクション またはロックの使用が含まれます。 スレッド セーフではない実装では、そうでないことを明示的に文書化する必要があります。

追加の保証は、プロバイダー/オブザーバー コントラクトの上のレイヤーで指定する必要があります。 実装者は、オブザーバー コントラクトに関するユーザーの混乱を避けるために追加の要件を課すときに、明確に呼び出す必要があります。

例外の処理

データ プロバイダーとオブザーバーの間の疎結合のため、オブザーバー デザイン パターンの例外は情報提供を目的としています。 これは、プロバイダーとオブザーバーがオブザーバー デザイン パターンの例外を処理する方法に影響します。

プロバイダー - OnError メソッドの呼び出し

OnErrorメソッドは、IObserver<T>.OnNext メソッドと同様に、オブザーバーへの情報メッセージとして意図されています。 ただし、 OnNext メソッドは、現在または更新されたデータをオブザーバーに提供するように設計されていますが、 OnError メソッドは、プロバイダーが有効なデータを提供できないことを示すように設計されています。

プロバイダーは、例外を処理し、 OnError メソッドを呼び出すときに、次のベスト プラクティスに従う必要があります。

  • 特定の要件がある場合、プロバイダーは独自の例外を処理する必要があります。

  • プロバイダーは、オブザーバーが特定の方法で例外を処理することを想定したり、要求したりしないでください。

  • プロバイダーは、更新プログラムを提供する機能を損なう例外を処理するときに、 OnError メソッドを呼び出す必要があります。 このような例外に関する情報は、オブザーバーに渡すことができます。 それ以外の場合は、オブザーバーに例外を通知する必要はありません。

プロバイダーが OnError メソッドまたは IObserver<T>.OnCompleted メソッドを呼び出すと、それ以上通知が表示されなくなり、プロバイダーはオブザーバーの登録を解除できます。 ただし、オブザーバーは、 OnError または IObserver<T>.OnCompleted 通知を受信する前と後の両方を含め、いつでもサブスクリプションを解除することもできます。 オブザーバーの設計パターンでは、プロバイダーまたはオブザーバーがサブスクライブ解除を担当するかどうかは決まります。そのため、両方とも登録解除を試みる可能性があります。 通常、オブザーバーがサブスクリプションを解除すると、サブスクライバー コレクションから削除されます。 シングル スレッド アプリケーションでは、 IDisposable.Dispose 実装では、オブジェクト参照が有効であること、およびオブジェクトがサブスクライバー コレクションのメンバーであることを確認してから削除する必要があります。 マルチスレッド アプリケーションでは、 System.Collections.Concurrent.BlockingCollection<T> オブジェクトなどのスレッド セーフなコレクション オブジェクトを使用する必要があります。

オブザーバー - OnError メソッドの実装

オブザーバーがプロバイダーからエラー通知を受信した場合、オブザーバーは例外を情報として扱う必要があり、特定のアクションを実行する必要はありません。

オブザーバーは、プロバイダーからの OnError メソッド呼び出しに応答するときに、次のベスト プラクティスに従う必要があります。

  • オブザーバーは、 OnNextOnErrorなどのインターフェイス実装から例外をスローしないでください。 ただし、オブザーバーが例外をスローする場合は、これらの例外がハンドルされないと想定する必要があります。

  • 呼び出し履歴を保持するには、OnError メソッドに渡されたException オブジェクトをスローするオブザーバーは、例外をスローする前にラップする必要があります。 この目的には、標準の例外オブジェクトを使用する必要があります。

その他のベスト プラクティス

IObservable<T>.Subscribe メソッドで登録を解除しようとすると、null 参照が発生する可能性があります。 そのため、この方法は避けてください。

オブザーバーを複数のプロバイダーにアタッチすることはできますが、推奨されるパターンは、 IObserver<T> インスタンスを 1 つの IObservable<T> インスタンスにのみアタッチすることです。

こちらも参照ください