オブザーバーの設計パターンでは、通知を登録するオブザーバーと、データを監視して 1 つ以上のオブザーバーに通知を送信するプロバイダーとの間の分割が必要です。 この記事では、オブザーバーを作成する方法について説明します。 関連記事「 プロバイダーを実装する方法」では、プロバイダーを作成する方法について説明します。
オブザーバーを作成する
オブザーバーを作成するには、 System.IObserver<T> インターフェイスを実装します。 次の手順では、定義する必要がある各メンバーについて説明します。
System.IObserver<T> インターフェイスを実装するオブザーバー型を定義します。
次のコードでは、
TemperatureReporterのジェネリック型引数を使用して構築されたSystem.IObserver<T>実装であるTemperatureという名前の型を定義します。namespace TemperatureSample; public sealed class TemperatureReporter : IObserver<Temperature>Namespace Global.TemperatureSample Public NotInheritable Class TemperatureReporter Implements IObserver(Of Temperature)プロバイダーがIObserver<T>.OnCompletedを呼び出す前にオブザーバーの登録を解除する必要がある場合は、IDisposableによって返されるIObservable<T>.Subscribeを保持するプライベート変数を定義し、サブスクリプション メソッドを定義します。
プライベート変数
unsubscriberIDisposable オブジェクトを格納します。Subscribeメソッドは、プロバイダーのSubscribe メソッドを呼び出し、返されたオブジェクトをunsubscriberに割り当てます。namespace TemperatureSample; public sealed class TemperatureReporter : IObserver<Temperature> { private IDisposable? _unsubscriber; private Temperature? _last; public void Subscribe(IObservable<Temperature> provider) { ArgumentNullException.ThrowIfNull(provider); _unsubscriber = provider.Subscribe(this); }Namespace Global.TemperatureSample Public NotInheritable Class TemperatureReporter Implements IObserver(Of Temperature) Private _unsubscriber As IDisposable Private _last As Temperature? Public Sub Subscribe(provider As IObservable(Of Temperature)) ArgumentNullException.ThrowIfNull(provider) _unsubscriber = provider.Subscribe(Me) End Subプロバイダーが
Unsubscribeを呼び出す前に、オブザーバーが通知の受信を停止できるようにするIObserver<T>.OnCompleted メソッドを定義します。public void Unsubscribe() => _unsubscriber?.Dispose();Public Sub Unsubscribe() _unsubscriber?.Dispose() End SubIObserver<T>で定義されている 3 つのメソッド (IObserver<T>.OnNext、IObserver<T>.OnError、IObserver<T>.OnCompleted) を実装します。
OnErrorメソッドと OnCompleted メソッドは、スタブ実装にすることができます。 OnError メソッドは、渡されたExceptionを例外として処理しないでください。また、OnCompletedはプロバイダーのIDisposable.Dispose実装を呼び出すことができます。
public void OnCompleted() => Console.WriteLine("Additional temperature data won't be transmitted."); // OnError is informational; observers shouldn't treat it as an exception to handle. public void OnError(Exception error) { } public void OnNext(Temperature value) { Console.WriteLine($"The temperature is {value.Degrees}°C at {value.Date:g}"); if (_last is Temperature previous) { TimeSpan elapsed = value.Date.ToUniversalTime() - previous.Date.ToUniversalTime(); Console.WriteLine($" Change: {value.Degrees - previous.Degrees}° in {elapsed:g}"); } _last = value; }Public Sub OnCompleted() Implements IObserver(Of Temperature).OnCompleted Console.WriteLine("Additional temperature data won't be transmitted.") End Sub ' OnError is informational; observers shouldn't treat it as an exception to handle. Public Sub OnError(error_ As Exception) Implements IObserver(Of Temperature).OnError End Sub Public Sub OnNext(value As Temperature) Implements IObserver(Of Temperature).OnNext Console.WriteLine($"The temperature is {value.Degrees}°C at {value.Date:g}") If _last.HasValue Then Dim previous = _last.Value Dim elapsed = value.Date.ToUniversalTime() - previous.Date.ToUniversalTime() Console.WriteLine($" Change: {value.Degrees - previous.Degrees}° in {elapsed:g}") End If _last = value End Sub
完全なコード例
次の例は、温度監視アプリケーションのTemperatureReporter実装を提供する、IObserver<T> クラスの完全なソース コードを示しています。
namespace TemperatureSample;
public sealed class TemperatureReporter : IObserver<Temperature>
{
private IDisposable? _unsubscriber;
private Temperature? _last;
public void Subscribe(IObservable<Temperature> provider)
{
ArgumentNullException.ThrowIfNull(provider);
_unsubscriber = provider.Subscribe(this);
}
public void Unsubscribe() => _unsubscriber?.Dispose();
public void OnCompleted() =>
Console.WriteLine("Additional temperature data won't be transmitted.");
// OnError is informational; observers shouldn't treat it as an exception to handle.
public void OnError(Exception error) { }
public void OnNext(Temperature value)
{
Console.WriteLine($"The temperature is {value.Degrees}°C at {value.Date:g}");
if (_last is Temperature previous)
{
TimeSpan elapsed = value.Date.ToUniversalTime() - previous.Date.ToUniversalTime();
Console.WriteLine($" Change: {value.Degrees - previous.Degrees}° in {elapsed:g}");
}
_last = value;
}
}
Namespace Global.TemperatureSample
Public NotInheritable Class TemperatureReporter
Implements IObserver(Of Temperature)
Private _unsubscriber As IDisposable
Private _last As Temperature?
Public Sub Subscribe(provider As IObservable(Of Temperature))
ArgumentNullException.ThrowIfNull(provider)
_unsubscriber = provider.Subscribe(Me)
End Sub
Public Sub Unsubscribe()
_unsubscriber?.Dispose()
End Sub
Public Sub OnCompleted() Implements IObserver(Of Temperature).OnCompleted
Console.WriteLine("Additional temperature data won't be transmitted.")
End Sub
' OnError is informational; observers shouldn't treat it as an exception to handle.
Public Sub OnError(error_ As Exception) Implements IObserver(Of Temperature).OnError
End Sub
Public Sub OnNext(value As Temperature) Implements IObserver(Of Temperature).OnNext
Console.WriteLine($"The temperature is {value.Degrees}°C at {value.Date:g}")
If _last.HasValue Then
Dim previous = _last.Value
Dim elapsed = value.Date.ToUniversalTime() - previous.Date.ToUniversalTime()
Console.WriteLine($" Change: {value.Degrees - previous.Degrees}° in {elapsed:g}")
End If
_last = value
End Sub
End Class
End Namespace
関連するコンテンツ
.NET