Jak implementovat pozorovatele

Vzor návrhu pozorovatele vyžaduje rozdělení mezi pozorovatelem, který zaregistruje oznámení, a poskytovatelem, který monitoruje data a odesílá oznámení jednomu nebo více pozorovatelům. Tento článek popisuje, jak vytvořit pozorovatele. Související článek, Postup implementace poskytovatele, popisuje, jak vytvořit zprostředkovatele.

Vytvoření pozorovatele

Pokud chcete vytvořit pozorovatele, implementujte System.IObserver<T> rozhraní. Následující kroky popisují jednotlivé členy, které potřebujete definovat.

  1. Definujte typ pozorovatele System.IObserver<T> , který implementuje rozhraní.

    Následující kód definuje typ s názvem TemperatureReporter, který je konstruovanou implementací System.IObserver<T> s argumentem obecného typu Temperature.

    namespace TemperatureSample;
    
    public sealed class TemperatureReporter : IObserver<Temperature>
    
    Namespace Global.TemperatureSample
    
        Public NotInheritable Class TemperatureReporter
            Implements IObserver(Of Temperature)
    
  2. Pokud pozorovatel potřebuje zrušit odběr předtím, než poskytovatel zavolá IObserver<T>.OnCompleted, definujte privátní proměnnou pro uložení IDisposable, které vrací IObservable<T>.Subscribe, a definujte metodu pro přihlášení k odběru.

    Privátní proměnná unsubscriber ukládá IDisposable objekt. Metoda Subscribe volá metodu Subscribe poskytovatele a přiřadí vrácený objekt .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
    
  3. Definujte metodu Unsubscribe , která pozorovateli umožní ukončit přijímání oznámení před voláním IObserver<T>.OnCompletedposkytovatele .

    public void Unsubscribe() => _unsubscriber?.Dispose();
    
    Public Sub Unsubscribe()
        _unsubscriber?.Dispose()
    End Sub
    
  4. Implementujte tři metody definované pomocí IObserver<T>: IObserver<T>.OnNext, IObserver<T>.OnError a IObserver<T>.OnCompleted.

    Metody OnError a OnCompleted mohou být prázdné implementace. Metoda OnError by neměla s předaným Exception zacházet jako s výjimkou a OnCompleted může volat implementaci metody IDisposable.Dispose poskytovatele.

    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
    

Kompletní příklad

Následující příklad ukazuje úplný zdrojový kód pro TemperatureReporter třídu, který poskytuje implementaci IObserver<T> pro aplikaci pro monitorování teploty.

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