From 4b3fdcf6c998fc677cd202457211d306da2be5fc Mon Sep 17 00:00:00 2001 From: albert-du <52804499+albert-du@users.noreply.github.com> Date: Tue, 1 Feb 2022 20:09:31 -0800 Subject: [PATCH 1/2] IObservable, IObserver F# snippets --- .../System/IObservableT/Overview/fs.fsproj | 11 +++++ .../System/IObservableT/Overview/observer.fs | 35 ++++++++++++++ .../System/IObservableT/Overview/program.fs | 24 ++++++++++ .../System/IObservableT/Overview/provider.fs | 47 +++++++++++++++++++ xml/System/IObservable`1.xml | 6 +++ xml/System/IObserver`1.xml | 8 ++++ 6 files changed, 131 insertions(+) create mode 100644 snippets/fsharp/System/IObservableT/Overview/fs.fsproj create mode 100644 snippets/fsharp/System/IObservableT/Overview/observer.fs create mode 100644 snippets/fsharp/System/IObservableT/Overview/program.fs create mode 100644 snippets/fsharp/System/IObservableT/Overview/provider.fs diff --git a/snippets/fsharp/System/IObservableT/Overview/fs.fsproj b/snippets/fsharp/System/IObservableT/Overview/fs.fsproj new file mode 100644 index 00000000000..131b26313d5 --- /dev/null +++ b/snippets/fsharp/System/IObservableT/Overview/fs.fsproj @@ -0,0 +1,11 @@ + + + Exe + net6.0 + + + + + + + \ No newline at end of file diff --git a/snippets/fsharp/System/IObservableT/Overview/observer.fs b/snippets/fsharp/System/IObservableT/Overview/observer.fs new file mode 100644 index 00000000000..4a03f57310a --- /dev/null +++ b/snippets/fsharp/System/IObservableT/Overview/observer.fs @@ -0,0 +1,35 @@ +namespace global + +// +open System + +type LocationReporter(name) = + let mutable unsubscriber = Unchecked.defaultof + + member _.Name = name + + member this.Subscribe(provider: IObservable) = + if provider <> null then + unsubscriber <- provider.Subscribe this + + member _.Unsubscribe() = + unsubscriber.Dispose() + + interface IObserver 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}" + // + +// \ No newline at end of file diff --git a/snippets/fsharp/System/IObservableT/Overview/program.fs b/snippets/fsharp/System/IObservableT/Overview/program.fs new file mode 100644 index 00000000000..1ce49115c3e --- /dev/null +++ b/snippets/fsharp/System/IObservableT/Overview/program.fs @@ -0,0 +1,24 @@ +module program + +// +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. +// \ No newline at end of file diff --git a/snippets/fsharp/System/IObservableT/Overview/provider.fs b/snippets/fsharp/System/IObservableT/Overview/provider.fs new file mode 100644 index 00000000000..933e2cfb7e5 --- /dev/null +++ b/snippets/fsharp/System/IObservableT/Overview/provider.fs @@ -0,0 +1,47 @@ +namespace global + +open System +open System.Collections.Generic + +// +[] +type Location = + { Latitude: double + Longitude: double } +// + +// +exception LocationUnknownException +// + +// +type Unsubscriber(observers: List>, observer: IObserver) = + interface IDisposable with + member _.Dispose() = + if observer <> null && observers.Contains observer then + observers.Remove observer |> ignore + +type LocationTracker() = + // + let observers = ResizeArray>() + + interface IObservable with + member _.Subscribe(observer) = + if observers.Contains observer |> not then + observers.Add observer + new Unsubscriber(observers, observer) + + // + member _.TrackLocation(loc: Nullable) = + 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() +// \ No newline at end of file diff --git a/xml/System/IObservable`1.xml b/xml/System/IObservable`1.xml index 615b33151a9..d5bfeb44db2 100644 --- a/xml/System/IObservable`1.xml +++ b/xml/System/IObservable`1.xml @@ -67,16 +67,19 @@ The following example illustrates the observer design pattern. It defines a `Location` class that contains latitude and longitude information. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/provider.cs" id="Snippet5"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/provider.fs" id="Snippet5"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/provider.vb" id="Snippet5"::: The `LocationTracker` class provides the implementation. Its `TrackLocation` method is passed a nullable `Location` object that contains the latitude and longitude data. If the `Location` value is not `null`, the `TrackLocation` method calls the method of each observer. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/provider.cs" id="Snippet6"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/provider.fs" id="Snippet6"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/provider.vb" id="Snippet6"::: If the `Location` value is `null`, the `TrackLocation` method instantiates a `LocationUnknownException` object, which is shown in the following example. It then calls each observer's method and passes it the `LocationUnknownException` object. Note that `LocationUnknownException` derives from , but does not add any new members. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/provider.cs" id="Snippet7"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/provider.fs" id="Snippet7"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/provider.vb" id="Snippet7"::: Observers register to receive notifications from a `TrackLocation` object by calling its method, which assigns a reference to the observer object to a private generic object. The method returns an `Unsubscriber` object, which is an implementation that enables observers to stop receiving notifications. The `LocationTracker` class also includes an `EndTransmission` method. When no further location data is available, the method calls each observer's method and then clears the internal list of observers. @@ -84,11 +87,13 @@ In this example, the `LocationReporter` class provides the implementation. It displays information about the current location to the console. Its constructor includes a `name` parameter, which enables the `LocationReporter` instance to identify itself in its string output. It also includes a `Subscribe` method, which wraps a call to the provider's method. This allows the method to assign the returned reference to a private variable. The `LocationReporter` class also includes an `Unsubscribe` method, which calls the method of the object that is returned by the method. The following code defines the `LocationReporter` class. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/observer.cs" id="Snippet8"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/observer.fs" id="Snippet8"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/observer.vb" id="Snippet8"::: The following code then instantiates the provider and the observer. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/program.cs" id="Snippet9"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/program.fs" id="Snippet9"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/module1.vb" id="Snippet9"::: ]]> @@ -155,6 +160,7 @@ The following example illustrates the method for an application that reports latitude and longitude information. It defines an collection object that stores references to all observers. It also returns a private class named `Unsubscriber` that implements the interface and enables subscribers to stop receiving event notifications. See the Example section of the topic for the complete example. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/provider.cs" id="Snippet13"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/provider.fs" id="Snippet13"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/provider.vb" id="Snippet13"::: ]]> diff --git a/xml/System/IObserver`1.xml b/xml/System/IObserver`1.xml index bbdc9c9bff1..38eb29d97d7 100644 --- a/xml/System/IObserver`1.xml +++ b/xml/System/IObserver`1.xml @@ -65,21 +65,25 @@ The following example illustrates the observer design pattern. It defines a `Location` class that contains latitude and longitude information. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/provider.cs" id="Snippet5"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/provider.fs" id="Snippet5"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/provider.vb" id="Snippet5"::: The `LocationReporter` class provides the implementation. It displays information about the current location to the console. Its constructor includes a `name` parameter, which allows the `LocationReporter` instance to identify itself in its string output. It also includes a `Subscribe` method, which wraps a call to the provider's method. This enables the method to assign the returned reference to a private variable. The `LocationReporter` class also includes an `Unsubscribe` method, which calls the method of the object returned by the method. The following code defines the `LocationReporter` class. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/observer.cs" id="Snippet8"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/observer.fs" id="Snippet8"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/observer.vb" id="Snippet8"::: The `LocationTracker` class provides the implementation. Its `TrackLocation` method is passed a nullable `Location` object that contains the latitude and longitude data. If the `Location` value is not `null`, the `TrackLocation` method calls the method of each observer. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/provider.cs" id="Snippet6"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/provider.fs" id="Snippet6"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/provider.vb" id="Snippet6"::: If the `Location` value is `null`, the `TrackLocation` method instantiates a `LocationNotFoundException` object, which is shown in the following example. It then calls each observer's method and passes it the `LocationNotFoundException` object. Note that `LocationNotFoundException` derives from but does not add any new members. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/provider.cs" id="Snippet7"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/provider.fs" id="Snippet7"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/provider.vb" id="Snippet7"::: Observers register to receive notifications from a `TrackLocation` object by calling its method, which assigns a reference to the observer object to a private generic object. The method returns an `Unsubscriber` object, which is an implementation that enables observers to stop receiving notifications. The `LocationTracker` class also includes an `EndTransmission` method. When no further location data is available, the method calls each observer's method and then clears the internal list of observers. @@ -87,6 +91,7 @@ The following code then instantiates the provider and the observer. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/program.cs" id="Snippet9"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/program.fs" id="Snippet9"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/module1.vb" id="Snippet9"::: ]]> @@ -142,6 +147,7 @@ The following example provides an implementation of the method in a latitude/longitude tracking application. The method simply reports that no further data is available and calls the provider's implementation. See the Example section of the topic for the complete example. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/observer.cs" id="Snippet11"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/observer.fs" id="Snippet11"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/observer.vb" id="Snippet11"::: ]]> @@ -199,6 +205,7 @@ The following example provides an implementation of the method in a latitude/longitude tracking application. The method simply reports that data is currently unavailable; it does not make use of the object passed to it as a parameter. See the Example section of the topic for the complete example. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/observer.cs" id="Snippet10"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/observer.fs" id="Snippet10"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/observer.vb" id="Snippet10"::: ]]> @@ -256,6 +263,7 @@ The following example provides an implementation of the method in a latitude/longitude tracking application. See the Example section of the topic for the complete example. :::code language="csharp" source="~/snippets/csharp/System/IObservableT/Overview/observer.cs" id="Snippet12"::: + :::code language="fsharp" source="~/snippets/fsharp/System/IObservableT/Overview/observer.fs" id="Snippet12"::: :::code language="vb" source="~/snippets/visualbasic/VS_Snippets_CLR_System/system.iobserver.class/vb/observer.vb" id="Snippet12"::: ]]> From f41b8c1048f56d8f723c666e18c705c0eaa4ba05 Mon Sep 17 00:00:00 2001 From: albert-du <52804499+albert-du@users.noreply.github.com> Date: Tue, 1 Feb 2022 20:12:17 -0800 Subject: [PATCH 2/2] List -> ResizeArray --- snippets/fsharp/System/IObservableT/Overview/provider.fs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/snippets/fsharp/System/IObservableT/Overview/provider.fs b/snippets/fsharp/System/IObservableT/Overview/provider.fs index 933e2cfb7e5..63417c3689f 100644 --- a/snippets/fsharp/System/IObservableT/Overview/provider.fs +++ b/snippets/fsharp/System/IObservableT/Overview/provider.fs @@ -1,7 +1,6 @@ namespace global open System -open System.Collections.Generic // [] @@ -15,7 +14,7 @@ exception LocationUnknownException // // -type Unsubscriber(observers: List>, observer: IObserver) = +type Unsubscriber(observers: ResizeArray>, observer: IObserver) = interface IDisposable with member _.Dispose() = if observer <> null && observers.Contains observer then