IObservable<T> 介面
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
定義推播式通知的提供者。
generic <typename T>
public interface class IObservable
public interface IObservable<out T>
type IObservable<'T> = interface
Public Interface IObservable(Of Out T)
類型參數
- 衍生
範例
以下範例說明觀察者設計模式。 它定義了一個 Location 包含緯度與經度資訊的類別。
public struct Location
{
double lat, lon;
public Location(double latitude, double longitude)
{
this.lat = latitude;
this.lon = longitude;
}
public double Latitude
{ get { return this.lat; } }
public double Longitude
{ get { return this.lon; } }
}
[<Struct>]
type Location =
{ Latitude: double
Longitude: double }
Public Structure Location
Dim lat, lon As Double
Public Sub New(ByVal latitude As Double, ByVal longitude As Double)
Me.lat = latitude
Me.lon = longitude
End Sub
Public ReadOnly Property Latitude As Double
Get
Return Me.lat
End Get
End Property
Public ReadOnly Property Longitude As Double
Get
Return Me.lon
End Get
End Property
End Structure
該 LocationTracker 類別提供 IObservable<T> 實作。 其 TrackLocation 方法傳遞一個可 Location 空的物件,該物件包含緯度與經度資料。 若Location值不null為 ,該方法呼叫TrackLocationOnNext每個觀察者的方法。
public class LocationTracker : IObservable<Location>
{
public LocationTracker()
{
observers = new List<IObserver<Location>>();
}
private List<IObserver<Location>> observers;
public IDisposable Subscribe(IObserver<Location> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
private class Unsubscriber : IDisposable
{
private List<IObserver<Location>>_observers;
private IObserver<Location> _observer;
public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
}
}
public void TrackLocation(Nullable<Location> loc)
{
foreach (var observer in observers) {
if (!loc.HasValue)
observer.OnError(new LocationUnknownException());
else
observer.OnNext(loc.Value);
}
}
public void EndTransmission()
{
foreach (var observer in observers.ToArray())
if (observers.Contains(observer))
observer.OnCompleted();
observers.Clear();
}
}
type Unsubscriber(observers: ResizeArray<IObserver<Location>>, observer: IObserver<Location>) =
interface IDisposable with
member _.Dispose() =
if observer <> null && observers.Contains observer then
observers.Remove observer |> ignore
type LocationTracker() =
let observers = ResizeArray<IObserver<Location>>()
interface IObservable<Location> with
member _.Subscribe(observer) =
if observers.Contains observer |> not then
observers.Add observer
new Unsubscriber(observers, observer)
member _.TrackLocation(loc: Nullable<Location>) =
for observer in observers do
if not loc.HasValue then
observer.OnError LocationUnknownException
else
observer.OnNext loc.Value
member _.EndTransmission() =
for observer in observers.ToArray() do
if observers.Contains observer then
observer.OnCompleted()
observers.Clear()
Public Class LocationTracker : Implements IObservable(Of Location)
Public Sub New()
observers = New List(Of IObserver(Of Location))
End Sub
Private observers As List(Of IObserver(Of Location))
Public Function Subscribe(ByVal observer As System.IObserver(Of Location)) As System.IDisposable _
Implements System.IObservable(Of Location).Subscribe
If Not observers.Contains(observer) Then
observers.Add(observer)
End If
Return New Unsubscriber(observers, observer)
End Function
Private Class Unsubscriber : Implements IDisposable
Private _observers As List(Of IObserver(Of Location))
Private _observer As IObserver(Of Location)
Public Sub New(ByVal observers As List(Of IObserver(Of Location)), ByVal observer As IObserver(Of Location))
Me._observers = observers
Me._observer = observer
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
If _observer IsNot Nothing AndAlso _observers.Contains(_observer) Then
_observers.Remove(_observer)
End If
End Sub
End Class
Public Sub TrackLocation(ByVal loc As Nullable(Of Location))
For Each observer In observers
If Not loc.HasValue Then
observer.OnError(New LocationUnknownException())
Else
observer.OnNext(loc.Value)
End If
Next
End Sub
Public Sub EndTransmission()
For Each observer In observers.ToArray()
If observers.Contains(observer) Then observer.OnCompleted()
Next
observers.Clear()
End Sub
End Class
若值Location為 ,該null方法實例化一個TrackLocation物件,LocationUnknownException如下範例所示。 接著它呼叫每位觀察者的方法 OnError ,並將該 LocationUnknownException 物件傳給該方法。 注意 從 LocationUnknownExceptionException衍生,但不新增任何成員。
public class LocationUnknownException : Exception
{
internal LocationUnknownException()
{ }
}
exception LocationUnknownException
Public Class LocationUnknownException : Inherits Exception
Friend Sub New()
End Sub
End Class
觀察者透過 LocationTracker 呼叫 IObservable<T>.Subscribe 物件的方法註冊接收通知,該方法會將觀察者物件的參考指派給一個私有的泛型 List<T> 物件。 該方法回傳一個 Unsubscriber 物件,這是一個 IDisposable 實作,使觀察者能夠停止接收通知。 這 LocationTracker 堂課也包含一種 EndTransmission 方法。 當沒有其他位置資料可用時,該方法會呼叫每位觀察者的方法 OnCompleted ,然後清除內部觀察者清單。
在此範例中,類別 LocationReporter 提供 IObserver<T> 實作。 它會顯示目前位置的資訊給主控台。 其建構子包含一個 name 參數,使實 LocationReporter 例能在其字串輸出中識別自身。 它還包含一個 Subscribe 方法,將呼叫包裝到提供者的方法 Subscribe 。 這讓方法能將回傳 IDisposable 的參考指派給私有變數。 該 LocationReporter 類別也包含一個 Unsubscribe 方法,該方法呼叫 IDisposable.Dispose 該方法回傳 IObservable<T>.Subscribe 的物件的方法。 以下程式碼定義了這個 LocationReporter 類別。
using System;
public class LocationReporter : IObserver<Location>
{
private IDisposable unsubscriber;
private string instName;
public LocationReporter(string name)
{
this.instName = name;
}
public string Name
{ get{ return this.instName; } }
public virtual void Subscribe(IObservable<Location> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public virtual void OnCompleted()
{
Console.WriteLine("The Location Tracker has completed transmitting data to {0}.", this.Name);
this.Unsubscribe();
}
public virtual void OnError(Exception e)
{
Console.WriteLine("{0}: The location cannot be determined.", this.Name);
}
public virtual void OnNext(Location value)
{
Console.WriteLine("{2}: The current location is {0}, {1}", value.Latitude, value.Longitude, this.Name);
}
public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
}
open System
type LocationReporter(name) =
let mutable unsubscriber = Unchecked.defaultof<IDisposable>
member _.Name = name
member this.Subscribe(provider: IObservable<Location>) =
if provider <> null then
unsubscriber <- provider.Subscribe this
member _.Unsubscribe() =
unsubscriber.Dispose()
interface IObserver<Location> with
member this.OnCompleted() =
printfn $"The Location Tracker has completed transmitting data to {name}."
this.Unsubscribe()
member _.OnError(_) =
printfn $"{name}: The location cannot be determined."
member _.OnNext(value) =
printfn $"{name}: The current location is {value.Latitude}, {value.Longitude}"
Public Class LocationReporter : Implements IObserver(Of Location)
Dim unsubscriber As IDisposable
Dim instName As String
Public Sub New(ByVal name As String)
Me.instName = name
End Sub
Public ReadOnly Property Name As String
Get
Return instName
End Get
End Property
Public Overridable Sub Subscribe(ByVal provider As IObservable(Of Location))
If provider Is Nothing Then Exit Sub
unsubscriber = provider.Subscribe(Me)
End Sub
Public Overridable Sub OnCompleted() Implements System.IObserver(Of Location).OnCompleted
Console.WriteLine("The Location Tracker has completed transmitting data to {0}.", Me.Name)
Me.Unsubscribe()
End Sub
Public Overridable Sub OnError(ByVal e As System.Exception) Implements System.IObserver(Of Location).OnError
Console.WriteLine("{0}: The location cannot be determined.", Me.Name)
End Sub
Public Overridable Sub OnNext(ByVal value As Location) Implements System.IObserver(Of Location).OnNext
Console.WriteLine("{2}: The current location is {0}, {1}", value.Latitude, value.Longitude, Me.Name)
End Sub
Public Overridable Sub Unsubscribe()
unsubscriber.Dispose()
End Sub
End Class
接著,以下程式碼實例化提供者與觀察者。
using System;
class Program
{
static void Main(string[] args)
{
// Define a provider and two observers.
LocationTracker provider = new LocationTracker();
LocationReporter reporter1 = new LocationReporter("FixedGPS");
reporter1.Subscribe(provider);
LocationReporter reporter2 = new LocationReporter("MobileGPS");
reporter2.Subscribe(provider);
provider.TrackLocation(new Location(47.6456, -122.1312));
reporter1.Unsubscribe();
provider.TrackLocation(new Location(47.6677, -122.1199));
provider.TrackLocation(null);
provider.EndTransmission();
}
}
// The example displays output similar to the following:
// FixedGPS: The current location is 47.6456, -122.1312
// MobileGPS: The current location is 47.6456, -122.1312
// MobileGPS: The current location is 47.6677, -122.1199
// MobileGPS: The location cannot be determined.
// The Location Tracker has completed transmitting data to MobileGPS.
open System
// Define a provider and two observers.
let provider = LocationTracker()
let reporter1 = LocationReporter "FixedGPS"
reporter1.Subscribe provider
let reporter2 = LocationReporter "MobileGPS"
reporter2.Subscribe provider
provider.TrackLocation { Latitude = 47.6456; Longitude = -122.1312 }
reporter1.Unsubscribe()
provider.TrackLocation { Latitude = 47.6677; Longitude = -122.1199 }
provider.TrackLocation(Nullable())
provider.EndTransmission()
// The example displays output similar to the following:
// FixedGPS: The current location is 47.6456, -122.1312
// MobileGPS: The current location is 47.6456, -122.1312
// MobileGPS: The current location is 47.6677, -122.1199
// MobileGPS: The location cannot be determined.
// The Location Tracker has completed transmitting data to MobileGPS.
Module Module1
Dim provider As LocationTracker
Sub Main()
' Define a provider and two observers.
provider = New LocationTracker()
Dim reporter1 As New LocationReporter("FixedGPS")
reporter1.Subscribe(provider)
Dim reporter2 As New LocationReporter("MobileGPS")
reporter2.Subscribe(provider)
provider.TrackLocation(New Location(47.6456, -122.1312))
reporter1.Unsubscribe()
provider.TrackLocation(New Location(47.6677, -122.1199))
provider.TrackLocation(Nothing)
provider.EndTransmission()
End Sub
End Module
' The example displays output similar to the following:
' FixedGPS: The current location is 47.6456, -122.1312
' MobileGPS: The current location is 47.6456, -122.1312
' MobileGPS: The current location is 47.6677, -122.1199
' MobileGPS: The location cannot be determined.
' The Location Tracker has completed transmitting data to MobileGPS.
備註
IObserver<T>與IObservable<T>介面提供了一種通用的推播式通知機制,也稱為觀察者設計模式。 介面 IObservable<T> 代表發送通知的類別(提供者); IObserver<T> 介面代表接收通知的類別(觀察者)。
T 代表提供通知資訊的類別。 在某些推播式通知中, IObserver<T> 實作 和 T 可以代表相同類型。
提供者必須實作一個單一方法, Subscribe表示觀察者想要接收基於推送的通知。 呼叫方法的使用者會傳遞觀察者的實例。 該方法回傳一個 IDisposable 實作,允許觀察者在提供者停止發送通知前隨時取消通知。
在任何特定時刻,給定提供者可能擁有零、一個或多個觀察者。 提供者負責儲存觀察者的參考資料並確保其有效性,然後才會發送通知。 介面 IObservable<T> 不假設觀察者數量或通知發送順序。
提供者透過呼叫 IObserver<T> 方法向觀察者發送以下三種通知:
最新數據。 提供者可以呼叫該 IObserver<T>.OnNext 方法,將包含當前資料、變更資料或新資料的物件傳遞給觀察者
T。錯誤條件。 提供者可以呼叫該 IObserver<T>.OnError 方法來通知觀察者發生了某些錯誤狀況。
沒有更多資料。 提供者可以呼叫該 IObserver<T>.OnCompleted 方法,通知觀察者其已完成通知發送。
方法
| 名稱 | Description |
|---|---|
| Subscribe(IObserver<T>) |
通知提供者觀察員將接收通知。 |