Taal

Een waarnemer implementeren

Het ontwerppatroon van de waarnemer vereist een verdeling tussen een waarnemer, die zich registreert voor meldingen en een provider, die gegevens bewaakt en meldingen verzendt naar een of meer waarnemers. In dit artikel wordt beschreven hoe u een waarnemer maakt. Een gerelateerd artikel, Een provider implementeren, beschrijft hoe u een provider maakt.

Een waarnemer maken

Als u een waarnemer wilt maken, implementeert u de System.IObserver<T> interface. In de volgende stappen wordt elk lid beschreven dat u moet definiëren.

  1. Definieer het waarnemerstype waarmee de System.IObserver<T> interface wordt geïmplementeerd.

    De volgende code definieert een type met de naam TemperatureReporter, dat een samengestelde System.IObserver<T>-implementatie is met een generiek typeargument van Temperature.

    namespace TemperatureSample;
    
    public sealed class TemperatureReporter : IObserver<Temperature>
    
    Namespace Global.TemperatureSample
    
        Public NotInheritable Class TemperatureReporter
            Implements IObserver(Of Temperature)
    
  2. Als de observer zich moet uitschrijven voordat de provider IObserver<T>.OnCompleted aanroept, declareert u een privévariabele om de door IObservable<T>.Subscribe geretourneerde IDisposable in op te slaan, en definieert u een abonneermethode.

    Met de privévariabele unsubscriber wordt het IDisposable object opgeslagen. De Subscribe methode roept de methode van Subscribe de provider aan en wijst het geretourneerde object toe aan 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. Definieer een Unsubscribe methode waarmee de waarnemer geen meldingen meer ontvangt voordat de provider aanroept IObserver<T>.OnCompleted.

    public void Unsubscribe() => _unsubscriber?.Dispose();
    
    Public Sub Unsubscribe()
        _unsubscriber?.Dispose()
    End Sub
    
  4. Implementeer de drie methoden die zijn gedefinieerd door IObserver<T>: IObserver<T>.OnNext, IObserver<T>.OnErroren IObserver<T>.OnCompleted.

    De OnError en OnCompleted methoden kunnen stub-implementaties zijn. De methode OnError mag de doorgegeven Exception niet als een uitzondering behandelen, en OnCompleted kan de implementatie van IDisposable.Dispose van de provider aanroepen.

    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
    

Volledig voorbeeld

In het volgende voorbeeld ziet u de volledige broncode voor de TemperatureReporter klasse, die de IObserver<T> implementatie biedt voor een toepassing voor temperatuurbewaking.

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