From 94401c5c97907be6d0c154ce3f94af49c3048a9f Mon Sep 17 00:00:00 2001 From: Chris Froussios Date: Tue, 12 May 2015 15:02:14 +0200 Subject: [PATCH 1/5] Examples 1.2 --- .../Chapter1/KeyTypes/AsyncSubjectExample.cs | 44 ++++++++++ .../KeyTypes/BehaviorSubjectExample.cs | 52 ++++++++++++ .../KeyTypes/ImplicitContractsExample.cs | 25 ++++++ .../Chapter1/KeyTypes/ObserverExample.cs | 52 ++++++++++++ .../Chapter1/KeyTypes/ReplaySubjectExample.cs | 80 +++++++++++++++++++ .../Chapter1/KeyTypes/SubjectExample.cs | 31 +++++++ 6 files changed, 284 insertions(+) create mode 100644 Examples/Examples/Chapter1/KeyTypes/AsyncSubjectExample.cs create mode 100644 Examples/Examples/Chapter1/KeyTypes/BehaviorSubjectExample.cs create mode 100644 Examples/Examples/Chapter1/KeyTypes/ImplicitContractsExample.cs create mode 100644 Examples/Examples/Chapter1/KeyTypes/ObserverExample.cs create mode 100644 Examples/Examples/Chapter1/KeyTypes/ReplaySubjectExample.cs create mode 100644 Examples/Examples/Chapter1/KeyTypes/SubjectExample.cs diff --git a/Examples/Examples/Chapter1/KeyTypes/AsyncSubjectExample.cs b/Examples/Examples/Chapter1/KeyTypes/AsyncSubjectExample.cs new file mode 100644 index 0000000..dd9337c --- /dev/null +++ b/Examples/Examples/Chapter1/KeyTypes/AsyncSubjectExample.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class AsyncSubjectExample + { + void Example1(string[] args) + { + var subject = new AsyncSubject(); + subject.OnNext("a"); + WriteSequenceToConsole(subject); + subject.OnNext("b"); + subject.OnNext("c"); + Console.ReadKey(); + } + + void Example2(string[] args) + { + var subject = new AsyncSubject(); + subject.OnNext("a"); + WriteSequenceToConsole(subject); + subject.OnNext("b"); + subject.OnNext("c"); + subject.OnCompleted(); + Console.ReadKey(); + + //c + } + + //Takes an IObservable as its parameter. + //Subject implements this interface. + static void WriteSequenceToConsole(IObservable sequence) + { + //The next two lines are equivalent. + //sequence.Subscribe(value=>Console.WriteLine(value)); + sequence.Subscribe(Console.WriteLine); + } + } +} diff --git a/Examples/Examples/Chapter1/KeyTypes/BehaviorSubjectExample.cs b/Examples/Examples/Chapter1/KeyTypes/BehaviorSubjectExample.cs new file mode 100644 index 0000000..a00f132 --- /dev/null +++ b/Examples/Examples/Chapter1/KeyTypes/BehaviorSubjectExample.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class BehaviorSubjectExample + { + public void BehaviorSubjectExample1() + { + //Need to provide a default value. + var subject = new BehaviorSubject("a"); + subject.Subscribe(Console.WriteLine); + + //a + } + + public void BehaviorSubjectExample2() + { + var subject = new BehaviorSubject("a"); + subject.OnNext("b"); + subject.Subscribe(Console.WriteLine); + + //b + } + + public void BehaviorSubjectExample3() + { + var subject = new BehaviorSubject("a"); + subject.OnNext("b"); + subject.Subscribe(Console.WriteLine); + subject.OnNext("c"); + subject.OnNext("d"); + + //b + //c + //d + } + + public void BehaviorSubjectCompletedExample() + { + var subject = new BehaviorSubject("a"); + subject.OnNext("b"); + subject.OnNext("c"); + subject.OnCompleted(); + subject.Subscribe(Console.WriteLine); + } + } +} diff --git a/Examples/Examples/Chapter1/KeyTypes/ImplicitContractsExample.cs b/Examples/Examples/Chapter1/KeyTypes/ImplicitContractsExample.cs new file mode 100644 index 0000000..26cc08f --- /dev/null +++ b/Examples/Examples/Chapter1/KeyTypes/ImplicitContractsExample.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class ImplicitContractsExample + { + public void SubjectInvalidUsageExample() + { + var subject = new Subject(); + subject.Subscribe(Console.WriteLine); + subject.OnNext("a"); + subject.OnNext("b"); + subject.OnCompleted(); + subject.OnNext("c"); + + //a + //b + } + } +} diff --git a/Examples/Examples/Chapter1/KeyTypes/ObserverExample.cs b/Examples/Examples/Chapter1/KeyTypes/ObserverExample.cs new file mode 100644 index 0000000..df92baa --- /dev/null +++ b/Examples/Examples/Chapter1/KeyTypes/ObserverExample.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Disposables; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class ObserverExample + { + public class MyConsoleObserver : IObserver + { + public void OnNext(T value) + { + Console.WriteLine("Received value {0}", value); + } + public void OnError(Exception error) + { + Console.WriteLine("Sequence faulted with {0}", error); + } + public void OnCompleted() + { + Console.WriteLine("Sequence terminated"); + } + } + + public class MySequenceOfNumbers : IObservable + { + public IDisposable Subscribe(IObserver observer) + { + observer.OnNext(1); + observer.OnNext(2); + observer.OnNext(3); + observer.OnCompleted(); + return Disposable.Empty; + } + } + + public void Run() + { + var numbers = new MySequenceOfNumbers(); + var observer = new MyConsoleObserver(); + numbers.Subscribe(observer); + + //Received value 1 + //Received value 2 + //Received value 3 + //Sequence terminated + } + } +} diff --git a/Examples/Examples/Chapter1/KeyTypes/ReplaySubjectExample.cs b/Examples/Examples/Chapter1/KeyTypes/ReplaySubjectExample.cs new file mode 100644 index 0000000..a8db130 --- /dev/null +++ b/Examples/Examples/Chapter1/KeyTypes/ReplaySubjectExample.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class ReplaySubjectExample + { + public void NoReplay(string[] args) + { + var subject = new Subject(); + subject.OnNext("a"); + WriteSequenceToConsole(subject); + subject.OnNext("b"); + subject.OnNext("c"); + Console.ReadKey(); + + //b + //c + } + + public void Replay(string[] args) + { + var subject = new ReplaySubject(); + subject.OnNext("a"); + WriteSequenceToConsole(subject); + subject.OnNext("b"); + subject.OnNext("c"); + + //a + //b + //c + } + + public void ReplaySubjectBufferExample() + { + var bufferSize = 2; + var subject = new ReplaySubject(bufferSize); + subject.OnNext("a"); + subject.OnNext("b"); + subject.OnNext("c"); + subject.Subscribe(Console.WriteLine); + subject.OnNext("d"); + + //b + //c + //d + } + + public void ReplaySubjectWindowExample() + { + var window = TimeSpan.FromMilliseconds(150); + var subject = new ReplaySubject(window); + subject.OnNext("w"); + Thread.Sleep(TimeSpan.FromMilliseconds(100)); + subject.OnNext("x"); + Thread.Sleep(TimeSpan.FromMilliseconds(100)); + subject.OnNext("y"); + subject.Subscribe(Console.WriteLine); + subject.OnNext("z"); + + //x + //y + //z + } + + //Takes an IObservable as its parameter. + //Subject implements this interface. + static void WriteSequenceToConsole(IObservable sequence) + { + //The next two lines are equivalent. + //sequence.Subscribe(value=>Console.WriteLine(value)); + sequence.Subscribe(Console.WriteLine); + } + } +} diff --git a/Examples/Examples/Chapter1/KeyTypes/SubjectExample.cs b/Examples/Examples/Chapter1/KeyTypes/SubjectExample.cs new file mode 100644 index 0000000..5f7cb94 --- /dev/null +++ b/Examples/Examples/Chapter1/KeyTypes/SubjectExample.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class SubjectExample + { + public void Run() + { + var subject = new Subject(); + WriteSequenceToConsole(subject); + subject.OnNext("a"); + subject.OnNext("b"); + subject.OnNext("c"); + Console.ReadKey(); + } + + //Takes an IObservable as its parameter. + //Subject implements this interface. + static void WriteSequenceToConsole(IObservable sequence) + { + //The next two lines are equivalent. + //sequence.Subscribe(value=>Console.WriteLine(value)); + sequence.Subscribe(Console.WriteLine); + } + } +} From 8cc9baf368b3e9b957711a3b9b80e992f788c1d1 Mon Sep 17 00:00:00 2001 From: Chris Froussios Date: Tue, 12 May 2015 15:02:24 +0200 Subject: [PATCH 2/5] Examples 1.3 --- .../LifetimeManagement/IDisposableExamples.cs | 110 ++++++++++++++++++ .../LifetimeManagement/Subscribing.cs | 38 ++++++ .../LifetimeManagement/Termination.cs | 24 ++++ .../LifetimeManagement/Unsubscribing.cs | 41 +++++++ 4 files changed, 213 insertions(+) create mode 100644 Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs create mode 100644 Examples/Examples/Chapter1/LifetimeManagement/Subscribing.cs create mode 100644 Examples/Examples/Chapter1/LifetimeManagement/Termination.cs create mode 100644 Examples/Examples/Chapter1/LifetimeManagement/Unsubscribing.cs diff --git a/Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs b/Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs new file mode 100644 index 0000000..fb0f8fc --- /dev/null +++ b/Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + public class TimeIt : IDisposable + { + private readonly string _name; + private readonly Stopwatch _watch; + public TimeIt(string name) + { + _name = name; + _watch = Stopwatch.StartNew(); + } + public void Dispose() + { + _watch.Stop(); + Console.WriteLine("{0} took {1}", _name, _watch.Elapsed); + } + } + + //Creates a scope for a console foreground color. When disposed, will return to + // the previous Console.ForegroundColor + public class ConsoleColor : IDisposable + { + private readonly System.ConsoleColor _previousColor; + public ConsoleColor(System.ConsoleColor color) + { + _previousColor = Console.ForegroundColor; + Console.ForegroundColor = color; + } + public void Dispose() + { + Console.ForegroundColor = _previousColor; + } + } + + class IDisposableExamples + { + private void DoSomeWork(string w) + { + switch (w) + { + case "B": + Thread.Sleep(TimeSpan.FromMilliseconds(1500)); + break; + case "A": + Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + break; + } + } + + private void Cleanup() + { + Thread.Sleep(TimeSpan.FromMilliseconds(300)); + } + + public void ExampleTimer() + { + using (new TimeIt("Outer scope")) + { + using (new TimeIt("Inner scope A")) + { + DoSomeWork("A"); + } + using (new TimeIt("Inner scope B")) + { + DoSomeWork("B"); + } + Cleanup(); + } + + //Inner scope A took 00:00:01.0000000 + //Inner scope B took 00:00:01.5000000 + //Outer scope took 00:00:02.8000000 + } + + public void ExampleConsoleColor() + { + Console.WriteLine("Normal color"); + using (new ConsoleColor(System.ConsoleColor.Red)) + { + Console.WriteLine("Now I am Red"); + using (new ConsoleColor(System.ConsoleColor.Green)) + { + Console.WriteLine("Now I am Green"); + } + Console.WriteLine("and back to Red"); + } + } + + public void ExampleDisposableUtils() + { + var disposable = Disposable.Create(() => Console.WriteLine("Being disposed.")); + Console.WriteLine("Calling dispose..."); + disposable.Dispose(); + Console.WriteLine("Calling again..."); + disposable.Dispose(); + + //Calling dispose... + //Being disposed. + //Calling again... + } + } +} diff --git a/Examples/Examples/Chapter1/LifetimeManagement/Subscribing.cs b/Examples/Examples/Chapter1/LifetimeManagement/Subscribing.cs new file mode 100644 index 0000000..9c77cbe --- /dev/null +++ b/Examples/Examples/Chapter1/LifetimeManagement/Subscribing.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class Subscribing + { + public void StructuredExceptionHandling() + { + var values = new Subject(); + try + { + values.Subscribe(value => Console.WriteLine("1st subscription received {0}", value)); + } + catch (Exception) + { + Console.WriteLine("Won't catch anything here!"); + } + values.OnNext(0); + //Exception will be thrown here causing the app to fail. + values.OnError(new Exception("Dummy exception")); + } + + public void RxExceptionHandling() + { + var values = new Subject(); + values.Subscribe( + value => Console.WriteLine("1st subscription received {0}", value), + ex => Console.WriteLine("Caught an exception : {0}", ex)); + values.OnNext(0); + values.OnError(new Exception("Dummy exception")); + } + } +} diff --git a/Examples/Examples/Chapter1/LifetimeManagement/Termination.cs b/Examples/Examples/Chapter1/LifetimeManagement/Termination.cs new file mode 100644 index 0000000..682ad14 --- /dev/null +++ b/Examples/Examples/Chapter1/LifetimeManagement/Termination.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class Termination + { + public void Example() + { + var subject = new Subject(); + subject.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + subject.OnCompleted(); + subject.OnNext(2); + + //Completed + } + } +} diff --git a/Examples/Examples/Chapter1/LifetimeManagement/Unsubscribing.cs b/Examples/Examples/Chapter1/LifetimeManagement/Unsubscribing.cs new file mode 100644 index 0000000..e6a935f --- /dev/null +++ b/Examples/Examples/Chapter1/LifetimeManagement/Unsubscribing.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class Unsubscribing + { + public void Example() + { + var values = new Subject(); + var firstSubscription = values.Subscribe(value => + Console.WriteLine("1st subscription received {0}", value)); + var secondSubscription = values.Subscribe(value => + Console.WriteLine("2nd subscription received {0}", value)); + values.OnNext(0); + values.OnNext(1); + values.OnNext(2); + values.OnNext(3); + firstSubscription.Dispose(); + Console.WriteLine("Disposed of 1st subscription"); + values.OnNext(4); + values.OnNext(5); + + //1st subscription received 0 + //2nd subscription received 0 + //1st subscription received 1 + //2nd subscription received 1 + //1st subscription received 2 + //2nd subscription received 2 + //1st subscription received 3 + //2nd subscription received 3 + //Disposed of 1st subscription + //2nd subscription received 4 + //2nd subscription received 5 + } + } +} From 10607eab4748d516f1809d6ad92d7a470a8ecc88 Mon Sep 17 00:00:00 2001 From: Chris Froussios Date: Mon, 6 Jul 2015 14:07:49 +0200 Subject: [PATCH 3/5] Added runnable examples --- .../LifetimeManagement/IDisposableExamples.cs | 1 + .../Chapter2/Aggregation/Aggregate.cs | 77 ++++++ .../Examples/Chapter2/Aggregation/Count.cs | 26 ++ .../Examples/Chapter2/Aggregation/GroupBy.cs | 29 +++ .../Examples/Chapter2/Aggregation/MinMaxBy.cs | 13 + .../Chapter2/Aggregation/MinMaxSumAverage.cs | 35 +++ .../Examples/Chapter2/Aggregation/Scan.cs | 104 ++++++++ Examples/Examples/Chapter2/Creating/Create.cs | 133 ++++++++++ .../Chapter2/Creating/FromEnumerable.cs | 13 + .../Examples/Chapter2/Creating/FromTask.cs | 24 ++ .../Examples/Chapter2/Creating/Generate.cs | 52 ++++ .../Examples/Chapter2/Creating/Interval.cs | 27 +++ Examples/Examples/Chapter2/Creating/Range.cs | 34 +++ .../Chapter2/Creating/SimpleFactories.cs | 62 +++++ Examples/Examples/Chapter2/Creating/Start.cs | 53 ++++ Examples/Examples/Chapter2/Creating/Timer.cs | 23 ++ Examples/Examples/Chapter2/Creating/Unfold.cs | 43 ++++ Examples/Examples/Chapter2/Inspection/All.cs | 38 +++ Examples/Examples/Chapter2/Inspection/Any.cs | 58 +++++ .../Examples/Chapter2/Inspection/Contains.cs | 36 +++ .../Chapter2/Inspection/DefaultIfEmpty.cs | 61 +++++ .../Examples/Chapter2/Inspection/ElementAt.cs | 36 +++ .../Chapter2/Inspection/SequenceEqual.cs | 48 ++++ .../Examples/Chapter2/Reducing/Distinct.cs | 78 ++++++ .../Chapter2/Reducing/IgnoreElements.cs | 36 +++ .../Examples/Chapter2/Reducing/SkipTake.cs | 40 +++ .../Chapter2/Reducing/SkipTakeLast.cs | 65 +++++ .../Chapter2/Reducing/SkipTakeUntil.cs | 62 +++++ .../Chapter2/Reducing/SkipTakeWhile.cs | 59 +++++ Examples/Examples/Chapter2/Reducing/Where.cs | 28 +++ .../Chapter2/Transformation/CastOfType.cs | 61 +++++ .../Chapter2/Transformation/Materialize.cs | 43 ++++ .../Chapter2/Transformation/Select.cs | 69 ++++++ .../Chapter2/Transformation/Selectmany.cs | 156 ++++++++++++ .../Transformation/TimestampTimeInterval.cs | 38 +++ .../Chapter3/CombiningSequences/Amb.cs | 56 +++++ .../CombiningSequences/AndThenWhen.cs | 81 +++++++ .../CombiningSequences/CombineLatest.cs | 39 +++ .../Chapter3/CombiningSequences/Concat.cs | 51 ++++ .../Chapter3/CombiningSequences/Merge.cs | 54 +++++ .../Chapter3/CombiningSequences/Provider.cs | 47 ++++ .../Chapter3/CombiningSequences/Repeat.cs | 32 +++ .../Chapter3/CombiningSequences/StartWith.cs | 30 +++ .../Chapter3/CombiningSequences/Switch.cs | 34 +++ .../Chapter3/CombiningSequences/Zip.cs | 68 ++++++ .../Examples/Chapter3/ErrorHandling/Catch.cs | 57 +++++ .../Chapter3/ErrorHandling/Finally.cs | 49 ++++ .../ErrorHandling/OnErrorResumeNext.cs | 13 + .../Examples/Chapter3/ErrorHandling/Retry.cs | 59 +++++ .../Examples/Chapter3/ErrorHandling/Using.cs | 48 ++++ Examples/Examples/Chapter3/HotAndCold/Cold.cs | 32 +++ .../Chapter3/HotAndCold/LazyEnumerable.cs | 58 +++++ .../Examples/Chapter3/HotAndCold/Multicast.cs | 33 +++ .../Examples/Chapter3/HotAndCold/Publish.cs | 112 +++++++++ .../Chapter3/HotAndCold/PublishLast.cs | 44 ++++ .../Examples/Chapter3/HotAndCold/RefCount.cs | 41 ++++ .../Examples/Chapter3/HotAndCold/Replay.cs | 38 +++ .../Chapter3/LeavingTheMonad/AwaitAsync.cs | 39 +++ .../Chapter3/LeavingTheMonad/ForEachAsync.cs | 63 +++++ .../Chapter3/LeavingTheMonad/ToArray.cs | 40 +++ .../Chapter3/LeavingTheMonad/ToEnumerable.cs | 32 +++ .../Chapter3/LeavingTheMonad/ToEvent.cs | 55 +++++ .../Chapter3/LeavingTheMonad/ToTask.cs | 39 +++ .../Chapter3/SideEffects/AsObservable.cs | 127 ++++++++++ Examples/Examples/Chapter3/SideEffects/Do.cs | 78 ++++++ .../Chapter3/SideEffects/ExternalState.cs | 66 +++++ .../Chapter3/SideEffects/SharedState.cs | 39 +++ .../Examples/Chapter3/TimeShifted/Buffer.cs | 228 ++++++++++++++++++ .../Examples/Chapter3/TimeShifted/Delay.cs | 39 +++ .../Examples/Chapter3/TimeShifted/Sample.cs | 23 ++ .../Examples/Chapter3/TimeShifted/Throttle.cs | 13 + .../Examples/Chapter3/TimeShifted/Timeout.cs | 46 ++++ .../Chapter4/Scheduling/CreateAsync.cs | 44 ++++ .../Chapter4/Scheduling/FileReader.cs | 95 ++++++++ .../Chapter4/Scheduling/SchedulerAsync.cs | 87 +++++++ .../Chapter4/Scheduling/Schedulers.cs | 150 ++++++++++++ .../Chapter4/Scheduling/SchedulersInDepth.cs | 140 +++++++++++ .../Chapter4/Scheduling/SingleThreaded.cs | 40 +++ .../Chapter4/Scheduling/SubscribeOn.cs | 50 ++++ .../SequencesOfCoincidence/GroupJoin.cs | 13 + .../Chapter4/SequencesOfCoincidence/Join.cs | 14 ++ .../Chapter4/SequencesOfCoincidence/Window.cs | 95 ++++++++ .../Chapter4/Testing/AdvancedFeatures.cs | 155 ++++++++++++ .../Chapter4/Testing/TestSchedulerExamples.cs | 142 +++++++++++ Examples/Examples/SampleExtensions.cs | 19 ++ 85 files changed, 4808 insertions(+) create mode 100644 Examples/Examples/Chapter2/Aggregation/Aggregate.cs create mode 100644 Examples/Examples/Chapter2/Aggregation/Count.cs create mode 100644 Examples/Examples/Chapter2/Aggregation/GroupBy.cs create mode 100644 Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs create mode 100644 Examples/Examples/Chapter2/Aggregation/MinMaxSumAverage.cs create mode 100644 Examples/Examples/Chapter2/Aggregation/Scan.cs create mode 100644 Examples/Examples/Chapter2/Creating/Create.cs create mode 100644 Examples/Examples/Chapter2/Creating/FromEnumerable.cs create mode 100644 Examples/Examples/Chapter2/Creating/FromTask.cs create mode 100644 Examples/Examples/Chapter2/Creating/Generate.cs create mode 100644 Examples/Examples/Chapter2/Creating/Interval.cs create mode 100644 Examples/Examples/Chapter2/Creating/Range.cs create mode 100644 Examples/Examples/Chapter2/Creating/SimpleFactories.cs create mode 100644 Examples/Examples/Chapter2/Creating/Start.cs create mode 100644 Examples/Examples/Chapter2/Creating/Timer.cs create mode 100644 Examples/Examples/Chapter2/Creating/Unfold.cs create mode 100644 Examples/Examples/Chapter2/Inspection/All.cs create mode 100644 Examples/Examples/Chapter2/Inspection/Any.cs create mode 100644 Examples/Examples/Chapter2/Inspection/Contains.cs create mode 100644 Examples/Examples/Chapter2/Inspection/DefaultIfEmpty.cs create mode 100644 Examples/Examples/Chapter2/Inspection/ElementAt.cs create mode 100644 Examples/Examples/Chapter2/Inspection/SequenceEqual.cs create mode 100644 Examples/Examples/Chapter2/Reducing/Distinct.cs create mode 100644 Examples/Examples/Chapter2/Reducing/IgnoreElements.cs create mode 100644 Examples/Examples/Chapter2/Reducing/SkipTake.cs create mode 100644 Examples/Examples/Chapter2/Reducing/SkipTakeLast.cs create mode 100644 Examples/Examples/Chapter2/Reducing/SkipTakeUntil.cs create mode 100644 Examples/Examples/Chapter2/Reducing/SkipTakeWhile.cs create mode 100644 Examples/Examples/Chapter2/Reducing/Where.cs create mode 100644 Examples/Examples/Chapter2/Transformation/CastOfType.cs create mode 100644 Examples/Examples/Chapter2/Transformation/Materialize.cs create mode 100644 Examples/Examples/Chapter2/Transformation/Select.cs create mode 100644 Examples/Examples/Chapter2/Transformation/Selectmany.cs create mode 100644 Examples/Examples/Chapter2/Transformation/TimestampTimeInterval.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/Amb.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/AndThenWhen.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/CombineLatest.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/Concat.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/Merge.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/Provider.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/Repeat.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/StartWith.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/Switch.cs create mode 100644 Examples/Examples/Chapter3/CombiningSequences/Zip.cs create mode 100644 Examples/Examples/Chapter3/ErrorHandling/Catch.cs create mode 100644 Examples/Examples/Chapter3/ErrorHandling/Finally.cs create mode 100644 Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs create mode 100644 Examples/Examples/Chapter3/ErrorHandling/Retry.cs create mode 100644 Examples/Examples/Chapter3/ErrorHandling/Using.cs create mode 100644 Examples/Examples/Chapter3/HotAndCold/Cold.cs create mode 100644 Examples/Examples/Chapter3/HotAndCold/LazyEnumerable.cs create mode 100644 Examples/Examples/Chapter3/HotAndCold/Multicast.cs create mode 100644 Examples/Examples/Chapter3/HotAndCold/Publish.cs create mode 100644 Examples/Examples/Chapter3/HotAndCold/PublishLast.cs create mode 100644 Examples/Examples/Chapter3/HotAndCold/RefCount.cs create mode 100644 Examples/Examples/Chapter3/HotAndCold/Replay.cs create mode 100644 Examples/Examples/Chapter3/LeavingTheMonad/AwaitAsync.cs create mode 100644 Examples/Examples/Chapter3/LeavingTheMonad/ForEachAsync.cs create mode 100644 Examples/Examples/Chapter3/LeavingTheMonad/ToArray.cs create mode 100644 Examples/Examples/Chapter3/LeavingTheMonad/ToEnumerable.cs create mode 100644 Examples/Examples/Chapter3/LeavingTheMonad/ToEvent.cs create mode 100644 Examples/Examples/Chapter3/LeavingTheMonad/ToTask.cs create mode 100644 Examples/Examples/Chapter3/SideEffects/AsObservable.cs create mode 100644 Examples/Examples/Chapter3/SideEffects/Do.cs create mode 100644 Examples/Examples/Chapter3/SideEffects/ExternalState.cs create mode 100644 Examples/Examples/Chapter3/SideEffects/SharedState.cs create mode 100644 Examples/Examples/Chapter3/TimeShifted/Buffer.cs create mode 100644 Examples/Examples/Chapter3/TimeShifted/Delay.cs create mode 100644 Examples/Examples/Chapter3/TimeShifted/Sample.cs create mode 100644 Examples/Examples/Chapter3/TimeShifted/Throttle.cs create mode 100644 Examples/Examples/Chapter3/TimeShifted/Timeout.cs create mode 100644 Examples/Examples/Chapter4/Scheduling/CreateAsync.cs create mode 100644 Examples/Examples/Chapter4/Scheduling/FileReader.cs create mode 100644 Examples/Examples/Chapter4/Scheduling/SchedulerAsync.cs create mode 100644 Examples/Examples/Chapter4/Scheduling/Schedulers.cs create mode 100644 Examples/Examples/Chapter4/Scheduling/SchedulersInDepth.cs create mode 100644 Examples/Examples/Chapter4/Scheduling/SingleThreaded.cs create mode 100644 Examples/Examples/Chapter4/Scheduling/SubscribeOn.cs create mode 100644 Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs create mode 100644 Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs create mode 100644 Examples/Examples/Chapter4/SequencesOfCoincidence/Window.cs create mode 100644 Examples/Examples/Chapter4/Testing/AdvancedFeatures.cs create mode 100644 Examples/Examples/Chapter4/Testing/TestSchedulerExamples.cs create mode 100644 Examples/Examples/SampleExtensions.cs diff --git a/Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs b/Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs index fb0f8fc..6b45e42 100644 --- a/Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs +++ b/Examples/Examples/Chapter1/LifetimeManagement/IDisposableExamples.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reactive.Disposables; using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/Examples/Examples/Chapter2/Aggregation/Aggregate.cs b/Examples/Examples/Chapter2/Aggregation/Aggregate.cs new file mode 100644 index 0000000..9b15471 --- /dev/null +++ b/Examples/Examples/Chapter2/Aggregation/Aggregate.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Aggregation +{ + class Aggregate + { + public void Examples() + { + var source = Observable.Range(0, 5); + + var sum = source.MySum(); + var count = source.MyCount(); + var min = source.MyMin(); + var max = source.MyMax(); + + sum.Dump("Custom Sum"); + count.Dump("Custom Count"); + min.Dump("Custom Min"); + max.Dump("Custom Max"); + + //Custom Sum--> 10 + //Custom Sum completed + //Custom Count-- > 5 + //Custom Count completed + //Custom Min-- > 0 + //Custom Min completed + //Custom Max-- > 4 + //Custom Max completed + + } + } + + + static class Extensions + { + public static IObservable MySum(this IObservable source) + { + return source.Aggregate(0, (acc, currentValue) => acc + currentValue); + } + + public static IObservable MyCount(this IObservable source) + { + return source.Aggregate(0, (acc, _) => acc + 1); + } + + public static IObservable MyMin(this IObservable source) + { + return source.Aggregate( + (min, current) => Comparer + .Default + .Compare(min, current) > 0 + ? current + : min); + } + + public static IObservable MyMax(this IObservable source) + { + var comparer = Comparer.Default; + Func max = + (x, y) => + { + if (comparer.Compare(x, y) < 0) + { + return y; + } + return x; + }; + return source.Aggregate(max); + } + } + +} diff --git a/Examples/Examples/Chapter2/Aggregation/Count.cs b/Examples/Examples/Chapter2/Aggregation/Count.cs new file mode 100644 index 0000000..37e2d4e --- /dev/null +++ b/Examples/Examples/Chapter2/Aggregation/Count.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Aggregation +{ + class Count + { + public void Example() + { + var numbers = Observable.Range(0, 3); + numbers.Dump("numbers"); + numbers.Count().Dump("count"); + + //numbers-- > 1 + //numbers-- > 2 + //numbers-- > 3 + //numbers Completed + //count-- > 3 + //count Completed + } + } +} diff --git a/Examples/Examples/Chapter2/Aggregation/GroupBy.cs b/Examples/Examples/Chapter2/Aggregation/GroupBy.cs new file mode 100644 index 0000000..d681706 --- /dev/null +++ b/Examples/Examples/Chapter2/Aggregation/GroupBy.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Aggregation +{ + class GroupBy + { + public void Example() + { + var source = Observable.Interval(TimeSpan.FromSeconds(0.1)).Take(10); + var group = source.GroupBy(i => i % 3); + group + .SelectMany(grp => + grp.Max() + .Select(value => new { grp.Key, value })) + .Dump("group"); + + //group-- >{ Key = 0, value = 9 } + //group-- >{ Key = 1, value = 7 } + //group-- >{ Key = 2, value = 8 } + //group completed + + } + } +} diff --git a/Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs b/Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs new file mode 100644 index 0000000..3d0d28f --- /dev/null +++ b/Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Aggregation +{ + class MinMaxBy + { + // TODO invent examples + } +} diff --git a/Examples/Examples/Chapter2/Aggregation/MinMaxSumAverage.cs b/Examples/Examples/Chapter2/Aggregation/MinMaxSumAverage.cs new file mode 100644 index 0000000..8c7dc5f --- /dev/null +++ b/Examples/Examples/Chapter2/Aggregation/MinMaxSumAverage.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Aggregation +{ + public class MinMaxSumAverage + { + public void Example() + { + var numbers = new Subject(); + numbers.Dump("numbers"); + numbers.Min().Dump("Min"); + numbers.Average().Dump("Average"); + numbers.OnNext(1); + numbers.OnNext(2); + numbers.OnNext(3); + numbers.OnCompleted(); + + //numbers-- > 1 + //numbers-- > 2 + //numbers-- > 3 + //numbers completed + //Min-- > 1 + //Min completed + //Average-- > 2 + //Average completed + + } + } +} diff --git a/Examples/Examples/Chapter2/Aggregation/Scan.cs b/Examples/Examples/Chapter2/Aggregation/Scan.cs new file mode 100644 index 0000000..da7c0b4 --- /dev/null +++ b/Examples/Examples/Chapter2/Aggregation/Scan.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Aggregation +{ + public class Scan + { + public void ExampleRunningSum() + { + var numbers = new Subject(); + var scan = numbers.Scan(0, (acc, current) => acc + current); + numbers.Dump("numbers"); + scan.Dump("scan"); + numbers.OnNext(1); + numbers.OnNext(2); + numbers.OnNext(3); + numbers.OnCompleted(); + + //numbers-- > 1 + //scan-- > 1 + //numbers-- > 2 + //scan-- > 3 + //numbers-- > 3 + //scan-- > 6 + //numbers completed + //scan completed + } + + public void ExampleMin() + { + var numbers = new Subject(); + var min = numbers.RunningMin(); + numbers.Dump("numbers"); + min.Dump("min"); + numbers.OnNext(1); + numbers.OnNext(2); + numbers.OnNext(3); + numbers.OnCompleted(); + + //numbers-- > 1 + //min-- > 1 + //numbers-- > 2 + //numbers-- > 3 + //numbers completed + //min completed + + + } + + public void ExampleMax() + { + var numbers = new Subject(); + var max = numbers.RunningMax(); + numbers.Dump("numbers"); + max.Dump("max"); + numbers.OnNext(1); + numbers.OnNext(2); + numbers.OnNext(3); + numbers.OnCompleted(); + + //numbers-- > 1 + //max-- > 1 + //numbers-- > 2 + //max-- > 2 + //numbers-- > 3 + //max-- > 3 + //numbers completed + //max completed + + } + } + + static class Extentions + { + public static IObservable RunningMin(this IObservable source) + { + var comparer = Comparer.Default; + Func minOf = (x, y) => comparer.Compare(x, y) < 0 ? x : y; + return source.Scan(minOf) + .DistinctUntilChanged(); + } + + public static IObservable RunningMax(this IObservable source) + { + return source.Scan(MaxOf) + .Distinct(); + } + + private static T MaxOf(T x, T y) + { + var comparer = Comparer.Default; + if (comparer.Compare(x, y) < 0) + { + return y; + } + return x; + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/Create.cs b/Examples/Examples/Chapter2/Creating/Create.cs new file mode 100644 index 0000000..ff187fe --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/Create.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Timers; + +namespace IntroToRx.Examples +{ + class Create + { + private IObservable BlockingMethod() + { + var subject = new ReplaySubject(); + subject.OnNext("a"); + subject.OnNext("b"); + subject.OnCompleted(); + Thread.Sleep(1000); + return subject; + } + + private IObservable NonBlocking() + { + return Observable.Create( + (IObserver observer) => + { + observer.OnNext("a"); + observer.OnNext("b"); + observer.OnCompleted(); + Thread.Sleep(1000); + return Disposable.Create(() => Console.WriteLine("Observer has unsubscribed")); + //or can return an Action like + //return () => Console.WriteLine("Observer has unsubscribed"); + }); + } + + public void ExampleBlockingNonblocking() + { + var sw = new Stopwatch(); + + sw.Restart(); + Console.WriteLine("Calling blocking @" + sw.ElapsedMilliseconds); + var source1 = BlockingMethod(); + Console.WriteLine("Subscribing to blocking @" + sw.ElapsedMilliseconds); + source1.Subscribe(Console.WriteLine); + Console.WriteLine("Completed @" + sw.ElapsedMilliseconds); + Console.WriteLine(); + sw.Restart(); + Console.WriteLine("Calling non-blocking @" + sw.ElapsedMilliseconds); + var source2 = NonBlocking(); + Console.WriteLine("Subscribing to non-blocking @" + sw.ElapsedMilliseconds); + source2.Subscribe(Console.WriteLine); + Console.WriteLine("Completed @" + sw.ElapsedMilliseconds); + + //Calling blocking @0 + //Subscribing to blocking @1024 + //a + //b + //Completed @1028 + // + //Calling non-blocking @0 + //Subscribing to non - blocking @80 + //a + //b + //Observer has unsubscribed + //Completed @1093 + + } + + public void NonBlocking_event_driven() + { + var ob = Observable.Create( + observer => + { + var timer = new System.Timers.Timer(); + timer.Interval = 1000; + timer.Elapsed += (s, e) => observer.OnNext("tick"); + timer.Elapsed += OnTimerElapsed; + timer.Start(); + return timer; + }); + var subscription = ob.Subscribe(Console.WriteLine); + Console.ReadLine(); + subscription.Dispose(); + + //tick + //01/01/2012 12:00:00 + //tick + //01/01/2012 12:00:01 + //tick + //01/01/2012 12:00:02 + } + + public void NonBlocking_event_driven2() + { + var ob = Observable.Create( + observer => + { + var timer = new System.Timers.Timer(); + timer.Enabled = true; + timer.Interval = 100; + timer.Elapsed += OnTimerElapsed; + timer.Start(); + return () => { + timer.Elapsed -= OnTimerElapsed; + timer.Dispose(); + }; + }); + var subscription = ob.Subscribe(Console.WriteLine); + Console.ReadLine(); + subscription.Dispose(); + + //tick + //01/01/2012 12:00:00 + //tick + //01/01/2012 12:00:01 + //tick + //01/01/2012 12:00:02 + } + + private void OnTimerElapsed(object sender, ElapsedEventArgs e) + { + Console.WriteLine(e.SignalTime); + } + + + } +} diff --git a/Examples/Examples/Chapter2/Creating/FromEnumerable.cs b/Examples/Examples/Chapter2/Creating/FromEnumerable.cs new file mode 100644 index 0000000..92c648a --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/FromEnumerable.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class FromEnumerable + { + // TODO invent example + } +} diff --git a/Examples/Examples/Chapter2/Creating/FromTask.cs b/Examples/Examples/Chapter2/Creating/FromTask.cs new file mode 100644 index 0000000..631ace5 --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/FromTask.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Threading.Tasks; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class FromTask + { + public void Example() + { + var t = Task.Factory.StartNew(() => "Test"); + var source = t.ToObservable(); + source.Subscribe( + Console.WriteLine, + () => Console.WriteLine("completed")); + + //Test + //Completed + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/Generate.cs b/Examples/Examples/Chapter2/Creating/Generate.cs new file mode 100644 index 0000000..6fbabf4 --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/Generate.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class Generate + { + public static IObservable Range(int start, int count) + { + var max = start + count; + return Observable.Generate( + start, + value => value < max, + value => value + 1, + value => value); + } + + public static IObservable Timer(TimeSpan dueTime) + { + return Observable.Generate( + 0L, + i => i < 1, + i => i + 1, + i => i, + i => dueTime); + } + + public static IObservable Timer(TimeSpan dueTime, TimeSpan period) + { + return Observable.Generate( + 0L, + i => true, + i => i + 1, + i => i, + i => i == 0 ? dueTime : period); + } + + public static IObservable Interval(TimeSpan period) + { + return Observable.Generate( + 0L, + i => true, + i => i + 1, + i => i, + i => period); + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/Interval.cs b/Examples/Examples/Chapter2/Creating/Interval.cs new file mode 100644 index 0000000..3fbac0b --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/Interval.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class Interval + { + public void Example() + { + var interval = Observable.Interval(TimeSpan.FromMilliseconds(250)); + interval.Subscribe( + Console.WriteLine, + () => Console.WriteLine("completed")); + + //0 + //1 + //2 + //3 + //4 + //5 + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/Range.cs b/Examples/Examples/Chapter2/Creating/Range.cs new file mode 100644 index 0000000..1cfdc5a --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/Range.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class Range + { + public void Example() + { + var range = Observable.Range(10, 15); + range.Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + + //10 + //11 + //12 + //13 + //14 + //15 + //16 + //17 + //18 + //19 + //20 + //21 + //22 + //23 + //24 + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/SimpleFactories.cs b/Examples/Examples/Chapter2/Creating/SimpleFactories.cs new file mode 100644 index 0000000..c2d8cb0 --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/SimpleFactories.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class SimpleFactories + { + //TODO: improve format + + public void ExampleReturn() + { + var singleValue = Observable.Return("Value"); + //which could have also been simulated with a replay subject + var subject = new ReplaySubject(); + subject.OnNext("Value"); + subject.OnCompleted(); + + singleValue.Subscribe(Console.WriteLine); + + //Value + } + + public void ExampleEmpty() + { + var empty = Observable.Empty(); + //Behaviorally equivalent to + var subject = new ReplaySubject(); + subject.OnCompleted(); + + empty.Subscribe(Console.WriteLine); + } + + public void ExampleNever() + { + var never = Observable.Never(); + //similar to a subject without notifications + var subject = new Subject(); + + never.Subscribe(Console.WriteLine); + } + + public void ExampleThrow() + { + var throws = Observable.Throw(new Exception()); + //Behaviorally equivalent to + var subject = new ReplaySubject(); + subject.OnError(new Exception()); + + throws.Subscribe( + Console.WriteLine, + Console.WriteLine, + Console.WriteLine); + + //System.Exception: Exception of type 'System.Exception' was thrown. + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/Start.cs b/Examples/Examples/Chapter2/Creating/Start.cs new file mode 100644 index 0000000..cf149a0 --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/Start.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + public class Start + { + public static void StartAction() + { + var start = Observable.Start(() => + { + Console.Write("Working away"); + for (int i = 0; i < 10; i++) + { + Thread.Sleep(100); + Console.Write("."); + } + }); + start.Subscribe( + unit => Console.WriteLine("Unit published"), + () => Console.WriteLine("Action completed")); + + //Working away..........Unit published + //Action completed + + } + + public static void StartFunc() + { + var start = Observable.Start(() => + { + Console.Write("Working away"); + for (int i = 0; i < 10; i++) + { + Thread.Sleep(100); + Console.Write("."); + } + return "Published value"; + }); + start.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Action completed")); + + //Working away..........Published value + //Action completed + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/Timer.cs b/Examples/Examples/Chapter2/Creating/Timer.cs new file mode 100644 index 0000000..1893ce4 --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/Timer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class Timer + { + public void Example() + { + var timer = Observable.Timer(TimeSpan.FromSeconds(1)); + timer.Subscribe( + Console.WriteLine, + () => Console.WriteLine("completed")); + + //0 + //completed + } + } +} diff --git a/Examples/Examples/Chapter2/Creating/Unfold.cs b/Examples/Examples/Chapter2/Creating/Unfold.cs new file mode 100644 index 0000000..8fc48e1 --- /dev/null +++ b/Examples/Examples/Chapter2/Creating/Unfold.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + class UnfoldExample + { + private static IEnumerable Unfold(T seed, Func accumulator) + { + var nextValue = seed; + while (true) + { + yield return nextValue; + nextValue = accumulator(nextValue); + } + } + + public void Example() + { + var naturalNumbers = Unfold(1, i => i + 1); + Console.WriteLine("1st 10 Natural numbers"); + foreach (var naturalNumber in naturalNumbers.Take(10)) + { + Console.WriteLine(naturalNumber); + } + + //1st 10 Natural numbers + //1 + //2 + //3 + //4 + //5 + //6 + //7 + //8 + //9 + //10 + } + } +} diff --git a/Examples/Examples/Chapter2/Inspection/All.cs b/Examples/Examples/Chapter2/Inspection/All.cs new file mode 100644 index 0000000..0e970d8 --- /dev/null +++ b/Examples/Examples/Chapter2/Inspection/All.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Inspection +{ + class All + { + public void Example() + { + var subject = new Subject(); + subject.Subscribe(Console.WriteLine, () => Console.WriteLine("Subject completed")); + var all = subject.All(i => i < 5); + all.Subscribe( + b => Console.WriteLine("All values less than 5? {0}", b), + () => Console.WriteLine("all completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(6); + subject.OnNext(2); + subject.OnNext(1); + subject.OnCompleted(); + + //1 + //2 + //6 + //All values less than 5? False + //all completed + //2 + //1 + //subject completed + } + } +} diff --git a/Examples/Examples/Chapter2/Inspection/Any.cs b/Examples/Examples/Chapter2/Inspection/Any.cs new file mode 100644 index 0000000..27d19b9 --- /dev/null +++ b/Examples/Examples/Chapter2/Inspection/Any.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Inspection +{ + class Any + { + public void Example1() + { + var subject = new Subject(); + subject.Subscribe(Console.WriteLine, () => Console.WriteLine("Subject completed")); + var any = subject.Any(); + any.Subscribe(b => Console.WriteLine("The subject has any values? {0}", b)); + subject.OnNext(1); + subject.OnCompleted(); + + //1 + //The subject has any values? True + //subject completed + } + + public void Example2() + { + var subject = new Subject(); + subject.Subscribe(Console.WriteLine, () => Console.WriteLine("Subject completed")); + var any = subject.Any(); + any.Subscribe(b => Console.WriteLine("The subject has any values? {0}", b)); + //subject.OnNext(1); + subject.OnCompleted(); + + //subject completed + //The subject has any values? False + } + + public void Example3() + { + var subject = new Subject(); + subject.Subscribe( + Console.WriteLine, + ex => Console.WriteLine("subject OnError : {0}", ex), + () => Console.WriteLine("Subject completed")); + var any = subject.Any(); + any.Subscribe( + b => Console.WriteLine("The subject has any values? {0}", b), + ex => Console.WriteLine(".Any() OnError : {0}", ex), + () => Console.WriteLine(".Any() completed")); + subject.OnError(new Exception()); + + //subject OnError : System.Exception: Fail + //.Any() OnError: System.Exception: Fail + } + } +} diff --git a/Examples/Examples/Chapter2/Inspection/Contains.cs b/Examples/Examples/Chapter2/Inspection/Contains.cs new file mode 100644 index 0000000..5a1a202 --- /dev/null +++ b/Examples/Examples/Chapter2/Inspection/Contains.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Inspection +{ + class Contains + { + public void Example() + { + var subject = new Subject(); + subject.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Subject completed")); + var contains = subject.Contains(2); + contains.Subscribe( + b => Console.WriteLine("Contains the value 2? {0}", b), + () => Console.WriteLine("contains completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnCompleted(); + + //1 + //2 + //Contains the value 2 ? True + //contains completed + //3 + //Subject completed + } + } +} diff --git a/Examples/Examples/Chapter2/Inspection/DefaultIfEmpty.cs b/Examples/Examples/Chapter2/Inspection/DefaultIfEmpty.cs new file mode 100644 index 0000000..ced973a --- /dev/null +++ b/Examples/Examples/Chapter2/Inspection/DefaultIfEmpty.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Inspection +{ + class DefaultIfEmpty + { + public void Example1() + { + var subject = new Subject(); + subject.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Subject completed")); + var defaultIfEmpty = subject.DefaultIfEmpty(); + defaultIfEmpty.Subscribe( + b => Console.WriteLine("defaultIfEmpty value: {0}", b), + () => Console.WriteLine("defaultIfEmpty completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnCompleted(); + + //1 + //defaultIfEmpty value: 1 + //2 + //defaultIfEmpty value: 2 + //3 + //defaultIfEmpty value: 3 + //Subject completed + //defaultIfEmpty completed + } + + public void Example2() + { + var subject = new Subject(); + subject.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Subject completed")); + var defaultIfEmpty = subject.DefaultIfEmpty(); + defaultIfEmpty.Subscribe( + b => Console.WriteLine("defaultIfEmpty value: {0}", b), + () => Console.WriteLine("defaultIfEmpty completed")); + var default42IfEmpty = subject.DefaultIfEmpty(42); + default42IfEmpty.Subscribe( + b => Console.WriteLine("default42IfEmpty value: {0}", b), + () => Console.WriteLine("default42IfEmpty completed")); + subject.OnCompleted(); + + //Subject completed + //defaultIfEmpty value: 0 + //defaultIfEmpty completed + //default42IfEmpty value: 42 + //default42IfEmpty completed + } + } +} diff --git a/Examples/Examples/Chapter2/Inspection/ElementAt.cs b/Examples/Examples/Chapter2/Inspection/ElementAt.cs new file mode 100644 index 0000000..077d4da --- /dev/null +++ b/Examples/Examples/Chapter2/Inspection/ElementAt.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Inspection +{ + class ElementAt + { + public void Example() + { + var subject = new Subject(); + subject.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Subject completed")); + var elementAt1 = subject.ElementAt(1); + elementAt1.Subscribe( + b => Console.WriteLine("elementAt1 value: {0}", b), + () => Console.WriteLine("elementAt1 completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnCompleted(); + + //1 + //2 + //elementAt1 value: 2 + //elementAt1 completed + //3 + //subject completed + } + } +} diff --git a/Examples/Examples/Chapter2/Inspection/SequenceEqual.cs b/Examples/Examples/Chapter2/Inspection/SequenceEqual.cs new file mode 100644 index 0000000..131ca3e --- /dev/null +++ b/Examples/Examples/Chapter2/Inspection/SequenceEqual.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Inspection +{ + class SequenceEqual + { + public void Example() + { + var subject1 = new Subject(); + subject1.Subscribe( + i => Console.WriteLine("subject1.OnNext({0})", i), + () => Console.WriteLine("subject1 completed")); + var subject2 = new Subject(); + subject2.Subscribe( + i => Console.WriteLine("subject2.OnNext({0})", i), + () => Console.WriteLine("subject2 completed")); + var areEqual = subject1.SequenceEqual(subject2); + areEqual.Subscribe( + i => Console.WriteLine("areEqual.OnNext({0})", i), + () => Console.WriteLine("areEqual completed")); + subject1.OnNext(1); + subject1.OnNext(2); + subject2.OnNext(1); + subject2.OnNext(2); + subject2.OnNext(3); + subject1.OnNext(3); + subject1.OnCompleted(); + subject2.OnCompleted(); + + //subject1.OnNext(1) + //subject1.OnNext(2) + //subject2.OnNext(1) + //subject2.OnNext(2) + //subject2.OnNext(3) + //subject1.OnNext(3) + //subject1 completed + //subject2 completed + //areEqual.OnNext(True) + //areEqual completed + } + } +} diff --git a/Examples/Examples/Chapter2/Reducing/Distinct.cs b/Examples/Examples/Chapter2/Reducing/Distinct.cs new file mode 100644 index 0000000..8ddc622 --- /dev/null +++ b/Examples/Examples/Chapter2/Reducing/Distinct.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Reducing +{ + class Distinct + { + public void ExampleDistinct() + { + var subject = new Subject(); + var distinct = subject.Distinct(); + subject.Subscribe( + i => Console.WriteLine("{0}", i), + () => Console.WriteLine("subject.OnCompleted()")); + distinct.Subscribe( + i => Console.WriteLine("distinct.OnNext({0})", i), + () => Console.WriteLine("distinct.OnCompleted()")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnNext(1); + subject.OnNext(1); + subject.OnNext(4); + subject.OnCompleted(); + + //1 + //distinct.OnNext(1) + //2 + //distinct.OnNext(2) + //3 + //distinct.OnNext(3) + //1 + //1 + //4 + //distinct.OnNext(4) + //subject.OnCompleted() + //distinct.OnCompleted() + } + + public void ExampleDistinctUntilChanged() + { + var subject = new Subject(); + var distinct = subject.DistinctUntilChanged(); + subject.Subscribe( + i => Console.WriteLine("{0}", i), + () => Console.WriteLine("subject.OnCompleted()")); + distinct.Subscribe( + i => Console.WriteLine("distinct.OnNext({0})", i), + () => Console.WriteLine("distinct.OnCompleted()")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnNext(1); + subject.OnNext(1); + subject.OnNext(4); + subject.OnCompleted(); + + //1 + //distinct.OnNext(1) + //2 + //distinct.OnNext(2) + //3 + //distinct.OnNext(3) + //1 + //distinct.OnNext(1) + //1 + //4 + //distinct.OnNext(4) + //subject.OnCompleted() + //distinct.OnCompleted() + } + } +} diff --git a/Examples/Examples/Chapter2/Reducing/IgnoreElements.cs b/Examples/Examples/Chapter2/Reducing/IgnoreElements.cs new file mode 100644 index 0000000..d45945a --- /dev/null +++ b/Examples/Examples/Chapter2/Reducing/IgnoreElements.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Reducing +{ + class IgnoreElements + { + public void Example() + { + var subject = new Subject(); + //Could use subject.Where(_=>false); + var noElements = subject.IgnoreElements(); + subject.Subscribe( + i => Console.WriteLine("subject.OnNext({0})", i), + () => Console.WriteLine("subject.OnCompleted()")); + noElements.Subscribe( + i => Console.WriteLine("noElements.OnNext({0})", i), + () => Console.WriteLine("noElements.OnCompleted()")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnCompleted(); + + //subject.OnNext(1) + //subject.OnNext(2) + //subject.OnNext(3) + //subject.OnCompleted() + //noElements.OnCompleted() + } + } +} diff --git a/Examples/Examples/Chapter2/Reducing/SkipTake.cs b/Examples/Examples/Chapter2/Reducing/SkipTake.cs new file mode 100644 index 0000000..e36ed6d --- /dev/null +++ b/Examples/Examples/Chapter2/Reducing/SkipTake.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Reducing +{ + class SkipTake + { + public void ExampleSkip() + { + Observable.Range(0, 10) + .Skip(3) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + + //3 + //4 + //5 + //6 + //7 + //8 + //9 + //Completed + } + + public void ExampleTake() + { + Observable.Range(0, 10) + .Take(3) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + + //0 + //1 + //2 + //Completed + } + } +} diff --git a/Examples/Examples/Chapter2/Reducing/SkipTakeLast.cs b/Examples/Examples/Chapter2/Reducing/SkipTakeLast.cs new file mode 100644 index 0000000..19d005e --- /dev/null +++ b/Examples/Examples/Chapter2/Reducing/SkipTakeLast.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Reducing +{ + class SkipTakeLast + { + public void ExampleSkipLast() + { + var subject = new Subject(); + subject + .SkipLast(2) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + Console.WriteLine("Pushing 1"); + subject.OnNext(1); + Console.WriteLine("Pushing 2"); + subject.OnNext(2); + Console.WriteLine("Pushing 3"); + subject.OnNext(3); + Console.WriteLine("Pushing 4"); + subject.OnNext(4); + subject.OnCompleted(); + + //Pushing 1 + //Pushing 2 + //Pushing 3 + //1 + //Pushing 4 + //2 + //Completed + } + + public void ExampleTakeLast() + { + var subject = new Subject(); + subject + .TakeLast(2) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + Console.WriteLine("Pushing 1"); + subject.OnNext(1); + Console.WriteLine("Pushing 2"); + subject.OnNext(2); + Console.WriteLine("Pushing 3"); + subject.OnNext(3); + Console.WriteLine("Pushing 4"); + subject.OnNext(4); + Console.WriteLine("Completing"); + subject.OnCompleted(); + + //Pushing 1 + //Pushing 2 + //Pushing 3 + //Pushing 4 + //Completing + //3 + //4 + //Completed + } + } +} diff --git a/Examples/Examples/Chapter2/Reducing/SkipTakeUntil.cs b/Examples/Examples/Chapter2/Reducing/SkipTakeUntil.cs new file mode 100644 index 0000000..60e7246 --- /dev/null +++ b/Examples/Examples/Chapter2/Reducing/SkipTakeUntil.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Reducing +{ + class SkipTakeUntil + { + public void ExampleSkipUntil() + { + var subject = new Subject(); + var otherSubject = new Subject(); + subject + .SkipUntil(otherSubject) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + otherSubject.OnNext(Unit.Default); + subject.OnNext(4); + subject.OnNext(5); + subject.OnNext(6); + subject.OnNext(7); + subject.OnCompleted(); + + //4 + //5 + //6 + //7 + //Completed + } + + public void ExampleTakeUntil() + { + var subject = new Subject(); + var otherSubject = new Subject(); + subject + .TakeUntil(otherSubject) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + otherSubject.OnNext(Unit.Default); + subject.OnNext(4); + subject.OnNext(5); + subject.OnNext(6); + subject.OnNext(7); + subject.OnNext(8); + subject.OnCompleted(); + + //1 + //2 + //3 + //Completed + } + } +} diff --git a/Examples/Examples/Chapter2/Reducing/SkipTakeWhile.cs b/Examples/Examples/Chapter2/Reducing/SkipTakeWhile.cs new file mode 100644 index 0000000..06ccc73 --- /dev/null +++ b/Examples/Examples/Chapter2/Reducing/SkipTakeWhile.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Reducing +{ + class SkipTakeWhile + { + public void ExampleSkip() + { + var subject = new Subject(); + subject + .SkipWhile(i => i < 4) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnNext(4); + subject.OnNext(3); + subject.OnNext(2); + subject.OnNext(1); + subject.OnNext(0); + subject.OnCompleted(); + + //4 + //3 + //2 + //1 + //0 + //Completed + } + + public void ExampleTake() + { + var subject = new Subject(); + subject + .TakeWhile(i => i < 4) + .Subscribe(Console.WriteLine, () => Console.WriteLine("Completed")); + subject.OnNext(1); + subject.OnNext(2); + subject.OnNext(3); + subject.OnNext(4); + subject.OnNext(3); + subject.OnNext(2); + subject.OnNext(1); + subject.OnNext(0); + subject.OnCompleted(); + + //1 + //2 + //3 + //Completed + } + } +} diff --git a/Examples/Examples/Chapter2/Reducing/Where.cs b/Examples/Examples/Chapter2/Reducing/Where.cs new file mode 100644 index 0000000..d6ebc71 --- /dev/null +++ b/Examples/Examples/Chapter2/Reducing/Where.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Reducing +{ + class Where + { + public void Example() + { + var oddNumbers = Observable.Range(0, 10) + .Where(i => i % 2 == 0) + .Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + + // 0 + // 2 + // 4 + // 6 + // 8 + // Completed + } + } +} diff --git a/Examples/Examples/Chapter2/Transformation/CastOfType.cs b/Examples/Examples/Chapter2/Transformation/CastOfType.cs new file mode 100644 index 0000000..f8a5e5a --- /dev/null +++ b/Examples/Examples/Chapter2/Transformation/CastOfType.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Threading; +using System.Reactive.Subjects; +using System.Reactive.Linq; + +namespace IntroToRx.Examples.Chapter2.Transformation +{ + public class CastOfType + { + public void ExampleCast1() + { + var objects = new Subject(); + objects.Cast().Dump("cast"); + objects.OnNext(1); + objects.OnNext(2); + objects.OnNext(3); + objects.OnCompleted(); + + //cast-->1 + //cast-->2 + //cast-->3 + //cast completed + } + + public void ExampleCastError() + { + var objects = new Subject(); + objects.Cast().Dump("cast"); + objects.OnNext(1); + objects.OnNext(2); + objects.OnNext("3");//Fail + + //cast-->1 + //cast-->2 + //cast failed --> Specified cast is not valid. + } + + public void ExampleOfType() + { + var objects = new Subject(); + objects.OfType().Dump("OfType"); + objects.OnNext(1); + objects.OnNext(2); + objects.OnNext("3");//Ignored + objects.OnNext(4); + objects.OnCompleted(); + + //OfType-->1 + //OfType-->2 + //OfType-->4 + //OfType completed + } + + + } +} \ No newline at end of file diff --git a/Examples/Examples/Chapter2/Transformation/Materialize.cs b/Examples/Examples/Chapter2/Transformation/Materialize.cs new file mode 100644 index 0000000..ec19aaa --- /dev/null +++ b/Examples/Examples/Chapter2/Transformation/Materialize.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Transformation +{ + class Materialize + { + public void Example() + { + Observable.Range(1, 3) + .Materialize() + .Dump("Materialize"); + + //Materialize-->OnNext(1) + //Materialize-->OnNext(2) + //Materialize-->OnNext(3) + //Materialize-->OnCompleted() + //Materialize completed + } + + public void ExampleOnError() + { + var source = new Subject(); + source.Materialize() + .Dump("Materialize"); + source.OnNext(1); + source.OnNext(2); + source.OnNext(3); + source.OnError(new Exception("Fail?")); + + //Materialize-->OnNext(1) + //Materialize-->OnNext(2) + //Materialize-->OnNext(3) + //Materialize-->OnError(System.Exception) + //Materialize completed + } + } +} diff --git a/Examples/Examples/Chapter2/Transformation/Select.cs b/Examples/Examples/Chapter2/Transformation/Select.cs new file mode 100644 index 0000000..37c070c --- /dev/null +++ b/Examples/Examples/Chapter2/Transformation/Select.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Transformation +{ + class Select + { + public void Example1() + { + var source = Observable.Range(0, 5); + source.Select(i => i + 3) + .Dump("+3"); + + //+3-->3 + //+3-->4 + //+3-->5 + //+3-->6 + //+3-->7 + //+3 completed + } + + public void Example2() + { + Observable.Range(1, 5) + .Select(i => (char)(i + 64)) + .Dump("char"); + + //char-->A + //char-->B + //char-->C + //char-->D + //char-->E + //char completed + } + + public void ExampleAnon() + { + Observable.Range(1, 5) + .Select( + i => new { Number = i, Character = (char)(i + 64) }) + .Dump("anon"); + + //anon-->{ Number = 1, Character = A } + //anon-->{ Number = 2, Character = B } + //anon-->{ Number = 3, Character = C } + //anon-->{ Number = 4, Character = D } + //anon-->{ Number = 5, Character = E } + //anon completed + } + + public void ExampleQCSyntax() + { + var query = from i in Observable.Range(1, 5) + select new { Number = i, Character = (char)(i + 64) }; + query.Dump("anon"); + + //anon-->{ Number = 1, Character = A } + //anon-->{ Number = 2, Character = B } + //anon-->{ Number = 3, Character = C } + //anon-->{ Number = 4, Character = D } + //anon-->{ Number = 5, Character = E } + //anon completed + } + } +} diff --git a/Examples/Examples/Chapter2/Transformation/Selectmany.cs b/Examples/Examples/Chapter2/Transformation/Selectmany.cs new file mode 100644 index 0000000..eb720b7 --- /dev/null +++ b/Examples/Examples/Chapter2/Transformation/Selectmany.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Transformation +{ + class SelectMany + { + public void Example() + { + Observable.Return(3) + .SelectMany(i => Observable.Range(1, i)) + .Dump("SelectMany"); + + //SelectMany-->1 + //SelectMany-->2 + //SelectMany-->3 + //SelectMany completed + } + + public void Example2() + { + Observable.Range(1, 3) + .SelectMany(i => Observable.Range(1, i)) + .Dump("SelectMany"); + + //SelectMany-->1 + //SelectMany-->1 + //SelectMany-->2 + //SelectMany-->1 + //SelectMany-->2 + //SelectMany-->3 + //SelectMany completed + } + + public void Example3() + { + Func letter = i => (char)(i + 64); + Observable.Return(1) + .SelectMany(i => Observable.Return(letter(i))) + .Dump("SelectMany"); + + //SelectMany-->A + //SelectMany completed + } + + public void Example4() + { + Func letter = i => (char)(i + 64); + Observable.Range(1, 3) + .SelectMany(i => Observable.Return(letter(i))) + .Dump("SelectMany"); + + //SelectMany-->A + //SelectMany-->B + //SelectMany-->C + } + + public void ExampleAlphabet() + { + Func letter = i => (char)(i + 64); + Observable.Range(1, 30) + .SelectMany( + i => + { + if (0 < i && i < 27) + { + return Observable.Return(letter(i)); + } + else + { + return Observable.Empty(); + } + }) + .Dump("SelectMany"); + + //SelectMany-->A + //SelectMany-->B + //SelectMany-->C + //SelectMany-->D + //SelectMany-->E + //SelectMany-->F + //SelectMany-->G + //SelectMany-->H + //SelectMany-->I + //SelectMany-->J + //SelectMany-->K + //SelectMany-->L + //SelectMany-->M + //SelectMany-->N + //SelectMany-->O + //SelectMany-->P + //SelectMany-->Q + //SelectMany-->R + //SelectMany-->S + //SelectMany-->T + //SelectMany-->U + //SelectMany-->V + //SelectMany-->W + //SelectMany-->X + //SelectMany-->Y + //SelectMany-->Z + //SelectMany completed + + } + + public void ExampleAsynchronous() + { + // Values [1,2,3] 3 seconds apart. + Observable.Interval(TimeSpan.FromSeconds(3)) + .Select(i => i + 1) //Values start at 0, so add 1. + .Take(3) //We only want 3 values + .SelectMany(GetSubValues) //project into child sequences + .Dump("SelectMany"); + } + + private IObservable GetSubValues(long offset) + { + //Produce values [x*10, (x*10)+1, (x*10)+2] 4 seconds apart, but starting immediately. + return Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(4)) + .Select(x => (offset * 10) + x) + .Take(3); + + //SelectMany-->10 + //SelectMany-->20 + //SelectMany-->11 + //SelectMany-->30 + //SelectMany-->21 + //SelectMany-->12 + //SelectMany-->31 + //SelectMany-->22 + //SelectMany-->32 + //SelectMany completed + } + + public void ExampleQCSyntax() + { + var query = from i in Observable.Range(1, 5) + where i % 2 == 0 + from j in GetSubValues(i) + select new { i, j }; + query.Dump("SelectMany"); + + //SelectMany-->{ i = 2, j = 20 } + //SelectMany-->{ i = 4, j = 40 } + //SelectMany-->{ i = 2, j = 21 } + //SelectMany-->{ i = 4, j = 41 } + //SelectMany-->{ i = 2, j = 22 } + //SelectMany-->{ i = 4, j = 42 } + //SelectMany completed + } + } +} diff --git a/Examples/Examples/Chapter2/Transformation/TimestampTimeInterval.cs b/Examples/Examples/Chapter2/Transformation/TimestampTimeInterval.cs new file mode 100644 index 0000000..cfde9e2 --- /dev/null +++ b/Examples/Examples/Chapter2/Transformation/TimestampTimeInterval.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter2.Transformation +{ + class TimestampTimeInterval + { + public void ExampleTimestamp() + { + Observable.Interval(TimeSpan.FromSeconds(1)) + .Take(3) + .Timestamp() + .Dump("TimeStamp"); + + //TimeStamp-->0@01/01/2012 12:00:01 a.m. +00:00 + //TimeStamp-->1@01/01/2012 12:00:02 a.m. +00:00 + //TimeStamp-->2@01/01/2012 12:00:03 a.m. +00:00 + //TimeStamp completed + } + + public void ExampleTimeInterval() + { + Observable.Interval(TimeSpan.FromSeconds(1)) + .Take(3) + .TimeInterval() + .Dump("TimeInterval"); + + //TimeInterval-->0@00:00:01.0180000 + //TimeInterval-->1@00:00:01.0010000 + //TimeInterval-->2@00:00:00.9980000 + //TimeInterval completed + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/Amb.cs b/Examples/Examples/Chapter3/CombiningSequences/Amb.cs new file mode 100644 index 0000000..896c15e --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/Amb.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class Amb + { + public void Example() + { + var s1 = new Subject(); + var s2 = new Subject(); + var s3 = new Subject(); + var result = Observable.Amb(s1, s2, s3); + result.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + s1.OnNext(1); + s2.OnNext(2); + s3.OnNext(3); + s1.OnNext(1); + s2.OnNext(2); + s3.OnNext(3); + s1.OnCompleted(); + s2.OnCompleted(); + s3.OnCompleted(); + + //1 + //1 + //Completed + } + + + + public void ExampleEager() + { + Provider.GetSequences().Amb().Dump("Amb"); + + //GetSequences() called + //Yield 1st sequence + //Yield 2nd sequence + //Yield 3rd sequence + //GetSequences() complete + //1st subscribed to + //2nd subscribed to + //3rd subscribed to + //Amb-->3 + //Amb completed + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/AndThenWhen.cs b/Examples/Examples/Chapter3/CombiningSequences/AndThenWhen.cs new file mode 100644 index 0000000..06563eb --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/AndThenWhen.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class AndThenWhen + { + public void ExampleUglyZip() + { + var one = Observable.Interval(TimeSpan.FromSeconds(1)).Take(5); + var two = Observable.Interval(TimeSpan.FromMilliseconds(250)).Take(10); + var three = Observable.Interval(TimeSpan.FromMilliseconds(150)).Take(14); + //lhs represents 'Left Hand Side' + //rhs represents 'Right Hand Side' + var zippedSequence = one + .Zip(two, (lhs, rhs) => new { One = lhs, Two = rhs }) + .Zip(three, (lhs, rhs) => new { One = lhs.One, Two = lhs.Two, Three = rhs }); + zippedSequence.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //{ One = 0, Two = 0, Three = 0 } + //{ One = 1, Two = 1, Three = 1 } + //{ One = 2, Two = 2, Three = 2 } + //{ One = 3, Two = 3, Three = 3 } + //{ One = 4, Two = 4, Three = 4 } + //Completed + } + + public void Example() + { + var one = Observable.Interval(TimeSpan.FromSeconds(1)).Take(5); + var two = Observable.Interval(TimeSpan.FromMilliseconds(250)).Take(10); + var three = Observable.Interval(TimeSpan.FromMilliseconds(150)).Take(14); + var pattern = one.And(two).And(three); + var plan = pattern.Then((first, second, third) => new { One = first, Two = second, Three = third }); + var zippedSequence = Observable.When(plan); + zippedSequence.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //{ One = 0, Two = 0, Three = 0 } + //{ One = 1, Two = 1, Three = 1 } + //{ One = 2, Two = 2, Three = 2 } + //{ One = 3, Two = 3, Three = 3 } + //{ One = 4, Two = 4, Three = 4 } + //Completed + } + + public void ExampleAlternative() + { + var one = Observable.Interval(TimeSpan.FromSeconds(1)).Take(5); + var two = Observable.Interval(TimeSpan.FromMilliseconds(250)).Take(10); + var three = Observable.Interval(TimeSpan.FromMilliseconds(150)).Take(14); + var zippedSequence = Observable.When( + one.And(two) + .And(three) + .Then((first, second, third) => + new { + One = first, + Two = second, + Three = third + }) + ); + zippedSequence.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //{ One = 0, Two = 0, Three = 0 } + //{ One = 1, Two = 1, Three = 1 } + //{ One = 2, Two = 2, Three = 2 } + //{ One = 3, Two = 3, Three = 3 } + //{ One = 4, Two = 4, Three = 4 } + //Completed + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/CombineLatest.cs b/Examples/Examples/Chapter3/CombiningSequences/CombineLatest.cs new file mode 100644 index 0000000..9e8fd65 --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/CombineLatest.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class CombineLatest + { + public void Example() + { + var webServerStatus = new Subject(); + var databaseStatus = new Subject(); + + //Yields true when both systems are up, and only on change of status + var systemStatus = webServerStatus + .CombineLatest( + databaseStatus, + (webStatus, dbStatus) => webStatus && dbStatus) + .StartWith(false) + .DistinctUntilChanged(); + systemStatus.Dump("System status"); + + webServerStatus.OnNext(true); + webServerStatus.OnNext(false); + databaseStatus.OnNext(true); + webServerStatus.OnNext(true); // Now they are both on + webServerStatus.OnNext(false); // and not anymore + + //System status-->False + //System status-->True + //System status-->False + } + + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/Concat.cs b/Examples/Examples/Chapter3/CombiningSequences/Concat.cs new file mode 100644 index 0000000..0d2ef3f --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/Concat.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class Concat + { + public void Example() + { + //Generate values 0,1,2 + var s1 = Observable.Range(0, 3); + //Generate values 5,6,7,8,9 + var s2 = Observable.Range(5, 5); + s1.Concat(s2) + .Subscribe(Console.WriteLine); + + //0 + //1 + //2 + //5 + //6 + //7 + //8 + //9 + } + + public void ExampleLaziness() + { + Provider.GetSequences().Concat().Dump("Concat"); + + //GetSequences() called + //Yield 1st sequence + //1st subscribed to + //Concat-->1 + //Yield 2nd sequence + //2nd subscribed to + //Concat-->2 + //Yield 3rd sequence + //3rd subscribed to + //Concat-->3 + //GetSequences() complete + //Concat completed + } + + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/Merge.cs b/Examples/Examples/Chapter3/CombiningSequences/Merge.cs new file mode 100644 index 0000000..3ac70c4 --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/Merge.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class Merge + { + public void Example() + { + //Generate values 0,1,2 + var s1 = Observable.Interval(TimeSpan.FromMilliseconds(250)) + .Take(3); + //Generate values 100,101,102,103,104 + var s2 = Observable.Interval(TimeSpan.FromMilliseconds(150)) + .Take(5) + .Select(i => i + 100); + s1.Merge(s2) + .Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //100 + //0 + //101 + //102 + //1 + //103 + //104 // Note this is a race condition. 2 could be + //2 // published before 104. + } + + public void ExampleSubscriptionsToSource() + { + Provider.GetSequences().Merge().Dump("Merge"); + + //GetSequences() called + //Yield 1st sequence + //1st subscribed to + //Yield 2nd sequence + //2nd subscribed to + //Merge-->2 + //Merge-->1 + //Yield 3rd sequence + //3rd subscribed to + //GetSequences() complete + //Merge-->3 + //Merge completed + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/Provider.cs b/Examples/Examples/Chapter3/CombiningSequences/Provider.cs new file mode 100644 index 0000000..eacc56b --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/Provider.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + /// + /// A provider for a simple example case + /// + static class Provider + { + public static IEnumerable> GetSequences() + { + Console.WriteLine("GetSequences() called"); + Console.WriteLine("Yield 1st sequence"); + yield return Observable.Create(o => + { + Console.WriteLine("1st subscribed to"); + return Observable.Timer(TimeSpan.FromMilliseconds(500)) + .Select(i => 1L) + .Subscribe(o); + }); + Console.WriteLine("Yield 2nd sequence"); + yield return Observable.Create(o => + { + Console.WriteLine("2nd subscribed to"); + return Observable.Timer(TimeSpan.FromMilliseconds(300)) + .Select(i => 2L) + .Subscribe(o); + }); + Thread.Sleep(1000); //Force a delay + Console.WriteLine("Yield 3rd sequence"); + yield return Observable.Create(o => + { + Console.WriteLine("3rd subscribed to"); + return Observable.Timer(TimeSpan.FromMilliseconds(100)) + .Select(i => 3L) + .Subscribe(o); + }); + Console.WriteLine("GetSequences() complete"); + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/Repeat.cs b/Examples/Examples/Chapter3/CombiningSequences/Repeat.cs new file mode 100644 index 0000000..8071e15 --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/Repeat.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class Repeat + { + public void Example() + { + var source = Observable.Range(0, 3); + var result = source.Repeat(3); + result.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //0 + //1 + //2 + //0 + //1 + //2 + //0 + //1 + //2 + //Completed + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/StartWith.cs b/Examples/Examples/Chapter3/CombiningSequences/StartWith.cs new file mode 100644 index 0000000..8929180 --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/StartWith.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class StartWith + { + public void Example() + { + //Generate values 0,1,2 + var source = Observable.Range(0, 3); + var result = source.StartWith(-3, -2, -1); + result.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //-3 + //-2 + //-1 + //0 + //1 + //2 + //Completed + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/Switch.cs b/Examples/Examples/Chapter3/CombiningSequences/Switch.cs new file mode 100644 index 0000000..b58e9a7 --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/Switch.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class Switch + { + public void Example() + { + var source = Observable.Interval(TimeSpan.FromMilliseconds(500)) + .Select(i => Observable.Interval(TimeSpan.FromMilliseconds(150)) + .Select(_ => i)); + + Observable.Switch(source) + .Take(9) + .Dump("Switch"); + + //Switch-->0 + //Switch-->0 + //Switch-->0 + //Switch-->1 + //Switch-->1 + //Switch-->1 + //Switch-->2 + //Switch-->2 + //Switch-->2 + //Switch completed + } + } +} diff --git a/Examples/Examples/Chapter3/CombiningSequences/Zip.cs b/Examples/Examples/Chapter3/CombiningSequences/Zip.cs new file mode 100644 index 0000000..7799dcf --- /dev/null +++ b/Examples/Examples/Chapter3/CombiningSequences/Zip.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.CombiningSequences +{ + class Zip + { + public void Example() + { + //Generate values 0,1,2 + var nums = Observable.Interval(TimeSpan.FromMilliseconds(250)) + .Take(3); + //Generate values a,b,c,d,e,f + var chars = Observable.Interval(TimeSpan.FromMilliseconds(150)) + .Take(6) + .Select(i => Char.ConvertFromUtf32((int)i + 97)); + //Zip values together + nums.Zip(chars, (lhs, rhs) => new { Left = lhs, Right = rhs }) + .Dump("Zip"); + + //Zip-->{ Left = 0, Right = a } + //Zip-->{ Left = 1, Right = b } + //Zip-->{ Left = 2, Right = c } + //Zip completed + } + + public class Coord + { + public int X { get; set; } + public int Y { get; set; } + public override string ToString() + { + return string.Format("{0},{1}", X, Y); + } + } + + public void ExampleCoords() + { + var mm = new Subject(); + var s1 = mm.Skip(1); + var delta = mm.Zip(s1, + (prev, curr) => new Coord + { + X = curr.X - prev.X, + Y = curr.Y - prev.Y + }); + delta.Subscribe( + Console.WriteLine, + () => Console.WriteLine("Completed")); + mm.OnNext(new Coord { X = 0, Y = 0 }); + mm.OnNext(new Coord { X = 1, Y = 0 }); //Move across 1 + mm.OnNext(new Coord { X = 3, Y = 2 }); //Diagonally up 2 + mm.OnNext(new Coord { X = 0, Y = 0 }); //Back to 0,0 + mm.OnCompleted(); + + //1,0 + //2,2 + //-3,-2 + //Completed + + } + } +} diff --git a/Examples/Examples/Chapter3/ErrorHandling/Catch.cs b/Examples/Examples/Chapter3/ErrorHandling/Catch.cs new file mode 100644 index 0000000..764efae --- /dev/null +++ b/Examples/Examples/Chapter3/ErrorHandling/Catch.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.ErrorHandling +{ + class Catch + { + public void ExampleSwallow() + { + var source = new Subject(); + var result = source.Catch(Observable.Empty()); + result.Dump("Catch"); + source.OnNext(1); + source.OnNext(2); + source.OnError(new Exception("Fail!")); + + //Catch-->1 + //Catch-->2 + //Catch completed + + } + + public void ExampleContinue() + { + var source = new Subject(); + var result = source.Catch(tx => Observable.Return(-1)); + result.Dump("Catch"); + source.OnNext(1); + source.OnNext(2); + source.OnError(new TimeoutException()); + + //Catch-->1 + //Catch-->2 + //Catch-->-1 + //Catch completed + } + + public void ExampleAllowThrough() + { + var source = new Subject(); + var result = source.Catch(tx => Observable.Return(-1)); + result.Dump("Catch"); + source.OnNext(1); + source.OnNext(2); + source.OnError(new ArgumentException("Fail!")); + + //Catch-->1 + //Catch-->2 + //Catch failed-->Fail! + } + } +} diff --git a/Examples/Examples/Chapter3/ErrorHandling/Finally.cs b/Examples/Examples/Chapter3/ErrorHandling/Finally.cs new file mode 100644 index 0000000..a9170b6 --- /dev/null +++ b/Examples/Examples/Chapter3/ErrorHandling/Finally.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.ErrorHandling +{ + class Finally + { + public void Example() + { + var source = new Subject(); + var result = source.Finally(() => Console.WriteLine("Finally action ran")); + result.Dump("Finally"); + source.OnNext(1); + source.OnNext(2); + source.OnNext(3); + source.OnCompleted(); + + //Finally-- > 1 + //Finally-- > 2 + //Finally-- > 3 + //Finally completed + //Finally action ran + } + + public void ExampleUnsubscription() + { + var source = new Subject(); + var result = source.Finally(() => Console.WriteLine("Finally")); + var subscription = result.Subscribe( + Console.WriteLine, + Console.WriteLine, + () => Console.WriteLine("Completed")); + source.OnNext(1); + source.OnNext(2); + source.OnNext(3); + subscription.Dispose(); + + //1 + //2 + //3 + //Finally + } + } +} diff --git a/Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs b/Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs new file mode 100644 index 0000000..42deee5 --- /dev/null +++ b/Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.ErrorHandling +{ + class OnErrorResumeNext + { + // TODO invent examples + } +} diff --git a/Examples/Examples/Chapter3/ErrorHandling/Retry.cs b/Examples/Examples/Chapter3/ErrorHandling/Retry.cs new file mode 100644 index 0000000..c25c072 --- /dev/null +++ b/Examples/Examples/Chapter3/ErrorHandling/Retry.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.ErrorHandling +{ + class Retry + { + public void Example() + { + var source = Observable.Create(o => + { + o.OnNext(0); + o.OnNext(1); + o.OnNext(2); + o.OnError(new Exception("Fail")); + return () => { }; + }); + source.Retry().Subscribe(t => Console.WriteLine(t)); //Will always retry + Console.ReadKey(); + + //0 + //1 + //2 + //0 + //1 + //2 + //0 + //1 + //2 + //... + } + + public void ExampleWithLimit() + { + var source = Observable.Create(o => + { + o.OnNext(0); + o.OnNext(1); + o.OnNext(2); + o.OnError(new Exception("Fail")); + return () => { }; + }); + source.Retry(2).Dump("Retry(2)"); + + //Retry(2)-->0 + //Retry(2)-->1 + //Retry(2)-->2 + //Retry(2)-->0 + //Retry(2)-->1 + //Retry(2)-->2 + //Retry(2) failed-->Fail + + } + } +} diff --git a/Examples/Examples/Chapter3/ErrorHandling/Using.cs b/Examples/Examples/Chapter3/ErrorHandling/Using.cs new file mode 100644 index 0000000..258b6bb --- /dev/null +++ b/Examples/Examples/Chapter3/ErrorHandling/Using.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.ErrorHandling +{ + + + class Using + { + public class TimeIt : IDisposable + { + private readonly string _name; + private readonly Stopwatch _watch; + public TimeIt(string name) + { + _name = name; + _watch = Stopwatch.StartNew(); + } + public void Dispose() + { + _watch.Stop(); + Console.WriteLine("{0} took {1}", _name, _watch.Elapsed); + } + } + + public void Example() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)); + var result = Observable.Using( + () => new TimeIt("Subscription Timer"), + timeIt => source); + result.Take(5).Dump("Using"); + + //Using-->0 + //Using-->1 + //Using-->2 + //Using-->3 + //Using-->4 + //Using completed + //Subscription Timer took 00:00:05.0138199 + } + } +} diff --git a/Examples/Examples/Chapter3/HotAndCold/Cold.cs b/Examples/Examples/Chapter3/HotAndCold/Cold.cs new file mode 100644 index 0000000..1b1e2cb --- /dev/null +++ b/Examples/Examples/Chapter3/HotAndCold/Cold.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.HotAndCold +{ + class Cold + { + public void SimpleColdSample() + { + var period = TimeSpan.FromSeconds(1); + var observable = Observable.Interval(period); + observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i)); + Thread.Sleep(period + TimeSpan.FromMilliseconds(50)); + observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i)); + Console.ReadKey(); + + //first subscription : 0 + //first subscription : 1 + //second subscription : 0 + //first subscription : 2 + //second subscription : 1 + //first subscription : 3 + //second subscription : 2 + //... + } + } +} diff --git a/Examples/Examples/Chapter3/HotAndCold/LazyEnumerable.cs b/Examples/Examples/Chapter3/HotAndCold/LazyEnumerable.cs new file mode 100644 index 0000000..e7d9ce3 --- /dev/null +++ b/Examples/Examples/Chapter3/HotAndCold/LazyEnumerable.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.HotAndCold +{ + class LazyEnumerable + { + public void ReadFirstValue(IEnumerable list) + { + foreach (var i in list) + { + Console.WriteLine("Read out first value of {0}", i); + break; + } + } + + public IEnumerable EagerEvaluation() + { + var result = new List(); + Console.WriteLine("About to return 1"); + result.Add(1); + //code below is executed but not used. + Console.WriteLine("About to return 2"); + result.Add(2); + return result; + } + + public void ExampleEager() + { + ReadFirstValue(EagerEvaluation()); + + //About to return 1 + //About to return 2 + //Read out first value of 1 + } + + public IEnumerable LazyEvaluation() + { + Console.WriteLine("About to return 1"); + yield return 1; + //Execution stops here in this example + Console.WriteLine("About to return 2"); + yield return 2; + } + + public void ExampleLazy() + { + ReadFirstValue(LazyEvaluation()); + + //About to return 1 + //Read out first value of 1 + } + + } +} diff --git a/Examples/Examples/Chapter3/HotAndCold/Multicast.cs b/Examples/Examples/Chapter3/HotAndCold/Multicast.cs new file mode 100644 index 0000000..1076d7c --- /dev/null +++ b/Examples/Examples/Chapter3/HotAndCold/Multicast.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.HotAndCold +{ + class Multicast + { + public void ExampleWithoutmulticast() + { + var period = TimeSpan.FromSeconds(1); + //var observable = Observable.Interval(period).Publish(); + var observable = Observable.Interval(period); + var shared = new Subject(); + shared.Subscribe(i => Console.WriteLine("first subscription : {0}", i)); + observable.Subscribe(shared); //'Connect' the observable. + Thread.Sleep(period); + Thread.Sleep(period); + shared.Subscribe(i => Console.WriteLine("second subscription : {0}", i)); + + //first subscription : 0 + //first subscription : 1 + //second subscription : 1 + //first subscription : 2 + //second subscription : 2 + } + } +} diff --git a/Examples/Examples/Chapter3/HotAndCold/Publish.cs b/Examples/Examples/Chapter3/HotAndCold/Publish.cs new file mode 100644 index 0000000..570b9d5 --- /dev/null +++ b/Examples/Examples/Chapter3/HotAndCold/Publish.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.HotAndCold +{ + class Publish + { + public void ExampleConnectBeforeSubscribe() + { + var period = TimeSpan.FromSeconds(1); + var observable = Observable.Interval(period).Publish(); + observable.Connect(); + observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i)); + Thread.Sleep(period + TimeSpan.FromMilliseconds(50)); + observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i)); + + //first subscription : 0 + //first subscription : 1 + //second subscription : 1 + //first subscription : 2 + //second subscription : 2 + //... + } + + public void ExampleSubscribeBeforeConnect() + { + var period = TimeSpan.FromSeconds(1); + var observable = Observable.Interval(period).Publish(); + observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i)); + Thread.Sleep(period + TimeSpan.FromMilliseconds(50)); + observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i)); + observable.Connect(); + + //first subscription : 0 + //second subscription : 0 + //first subscription : 1 + //second subscription : 1 + //first subscription : 2 + //second subscription : 2 + } + + public void ExampleInteractiveDisconnect() + { + var period = TimeSpan.FromSeconds(1); + var observable = Observable.Interval(period).Publish(); + observable.Subscribe(i => Console.WriteLine("subscription : {0}", i)); + var exit = false; + while (!exit) + { + Console.WriteLine("Press enter to connect, esc to exit."); + var key = Console.ReadKey(true); + if (key.Key == ConsoleKey.Enter) + { + var connection = observable.Connect(); //--Connects here-- + Console.WriteLine("Press any key to dispose of connection."); + Console.ReadKey(); + connection.Dispose(); //--Disconnects here-- + } + if (key.Key == ConsoleKey.Escape) + { + exit = true; + } + } + + //Press enter to connect, esc to exit. + //Press any key to dispose of connection. + //subscription : 0 + //subscription: 1 + //subscription: 2 + //Press enter to connect, esc to exit. + //Press any key to dispose of connection. + //subscription : 0 + //subscription: 1 + //subscription: 2 + //Press enter to connect, esc to exit. + } + + public void ExampleAutomaticDisconnect() + { + var period = TimeSpan.FromSeconds(1); + var observable = Observable.Interval(period) + .Do(l => Console.WriteLine("Publishing {0}", l)) //Side effect to show it is running + .Publish(); + observable.Connect(); + Console.WriteLine("Press any key to subscribe"); + Console.ReadKey(); + var subscription = observable.Subscribe(i => Console.WriteLine("subscription : {0}", i)); + Console.WriteLine("Press any key to unsubscribe."); + Console.ReadKey(); + subscription.Dispose(); + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + + //Press any key to subscribe + //Publishing 0 + //Publishing 1 + //Press any key to unsubscribe. + //Publishing 2 + //subscription: 2 + //Publishing 3 + //subscription: 3 + //Press any key to exit. + //Publishing 4 + //Publishing 5 + } + } +} diff --git a/Examples/Examples/Chapter3/HotAndCold/PublishLast.cs b/Examples/Examples/Chapter3/HotAndCold/PublishLast.cs new file mode 100644 index 0000000..317a2e6 --- /dev/null +++ b/Examples/Examples/Chapter3/HotAndCold/PublishLast.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.HotAndCold +{ + class PublishLast + { + public void Example() + { + var period = TimeSpan.FromSeconds(1); + var observable = Observable.Interval(period) + .Take(5) + .Do(l => Console.WriteLine("Publishing {0}", l)) //side effect to show it is running + //.PublishLast(); + .Multicast(new AsyncSubject()); + observable.Connect(); + Console.WriteLine("Press any key to subscribe"); + Console.ReadKey(); + var subscription = observable.Subscribe(i => Console.WriteLine("subscription : {0}", i)); + Console.WriteLine("Press any key to unsubscribe."); + Console.ReadKey(); + subscription.Dispose(); + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + + //Press any key to subscribe + //Publishing 0 + //Publishing 1 + //Publishing 2 + //Publishing 3 + //Press any key to unsubscribe. + //Publishing 4 + //subscription: 4 + //Press any key to exit. + + + } + } +} diff --git a/Examples/Examples/Chapter3/HotAndCold/RefCount.cs b/Examples/Examples/Chapter3/HotAndCold/RefCount.cs new file mode 100644 index 0000000..6d90a71 --- /dev/null +++ b/Examples/Examples/Chapter3/HotAndCold/RefCount.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.HotAndCold +{ + class RefCount + { + public void Example() + { + var period = TimeSpan.FromSeconds(1); + var observable = Observable.Interval(period) + .Do(l => Console.WriteLine("Publishing {0}", l)) //side effect to show it is running + .Publish() + .RefCount(); + //observable.Connect(); Use RefCount instead now + Console.WriteLine("Press any key to subscribe"); + Console.ReadKey(); + var subscription = observable.Subscribe(i => Console.WriteLine("subscription : {0}", i)); + Console.WriteLine("Press any key to unsubscribe."); + Console.ReadKey(); + subscription.Dispose(); + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + + //Press any key to subscribe + //Press any key to unsubscribe. + //Publishing 0 + //subscription : 0 + //Publishing 1 + //subscription : 1 + //Publishing 2 + //subscription : 2 + //Press any key to exit. + + } + } +} diff --git a/Examples/Examples/Chapter3/HotAndCold/Replay.cs b/Examples/Examples/Chapter3/HotAndCold/Replay.cs new file mode 100644 index 0000000..646383c --- /dev/null +++ b/Examples/Examples/Chapter3/HotAndCold/Replay.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.HotAndCold +{ + class Replay + { + public void Example() + { + var period = TimeSpan.FromSeconds(1); + var hot = Observable.Interval(period) + .Take(3) + .Publish(); + hot.Connect(); + Thread.Sleep(period); //Run hot and ensure a value is lost. + var observable = hot.Replay(); + observable.Connect(); + observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i)); + Thread.Sleep(period); + observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i)); + Console.ReadKey(); + observable.Subscribe(i => Console.WriteLine("third subscription : {0}", i)); + Console.ReadKey(); + + //first subscription : 1 + //second subscription : 1 + //first subscription : 2 + //second subscription : 2 + //third subscription : 1 + //third subscription : 2 + } + } +} diff --git a/Examples/Examples/Chapter3/LeavingTheMonad/AwaitAsync.cs b/Examples/Examples/Chapter3/LeavingTheMonad/AwaitAsync.cs new file mode 100644 index 0000000..4809f10 --- /dev/null +++ b/Examples/Examples/Chapter3/LeavingTheMonad/AwaitAsync.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.LeavingTheMonad +{ + class AwaitAsync + { + public async void Example() + { + var interval = Observable.Interval(TimeSpan.FromSeconds(1)); + // Will block for 3s before returning + Console.WriteLine(await interval.Take(3)); + Console.WriteLine("Completed"); + + //2 + //Completed + } + + public async void ExampleError() + { + var interval = Observable.Empty(); + try + { + Console.WriteLine(await interval.Take(3)); + Console.WriteLine("Completed"); + } + catch (Exception e) + { + Console.WriteLine("Error: " + e); + } + + //Error: System.InvalidOperationException: Sequence contains no elements. + } + } +} diff --git a/Examples/Examples/Chapter3/LeavingTheMonad/ForEachAsync.cs b/Examples/Examples/Chapter3/LeavingTheMonad/ForEachAsync.cs new file mode 100644 index 0000000..b603abe --- /dev/null +++ b/Examples/Examples/Chapter3/LeavingTheMonad/ForEachAsync.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.LeavingTheMonad +{ + class ForEachAsync + { + public async void Example() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)) + .Take(5); + var printing = source.ForEachAsync(i => Console.WriteLine("received {0} @ {1}", i, DateTime.Now)); + await printing; // Wait for every value to be printed + Console.WriteLine("completed @ {0}", DateTime.Now); + + //received 0 @ 01/01/2012 12:00:01 a.m. + //received 1 @ 01/01/2012 12:00:02 a.m. + //received 2 @ 01/01/2012 12:00:03 a.m. + //received 3 @ 01/01/2012 12:00:04 a.m. + //received 4 @ 01/01/2012 12:00:05 a.m. + //completed @ 01/01/2012 12:00:05 a.m. + } + + public void ExampleSubscribe() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)) + .Take(5); + source.Subscribe(i => Console.WriteLine("received {0} @ {1}", i, DateTime.Now)); + Console.WriteLine("completed @ {0}", DateTime.Now); + + //completed @ 01/01/2012 12:00:00 a.m. + //received 0 @ 01/01/2012 12:00:01 a.m. + //received 1 @ 01/01/2012 12:00:02 a.m. + //received 2 @ 01/01/2012 12:00:03 a.m. + //received 3 @ 01/01/2012 12:00:04 a.m. + //received 4 @ 01/01/2012 12:00:05 a.m. + } + + public async void ExampleOnError() + { + var source = Observable.Throw(new Exception("Fail")); + try + { + await source.ForEachAsync(Console.WriteLine); + } + catch (Exception ex) + { + Console.WriteLine("error @ {0} with {1}", DateTime.Now, ex.Message); + } + finally + { + Console.WriteLine("completed @ {0}", DateTime.Now); + } + + //error @ 01/01/2012 12:00:00 a.m. with Fail + //completed @ 01/01/2012 12:00:00 a.m. + } + } +} diff --git a/Examples/Examples/Chapter3/LeavingTheMonad/ToArray.cs b/Examples/Examples/Chapter3/LeavingTheMonad/ToArray.cs new file mode 100644 index 0000000..818fb2d --- /dev/null +++ b/Examples/Examples/Chapter3/LeavingTheMonad/ToArray.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.LeavingTheMonad +{ + class ToArray + { + public void Example() + { + var period = TimeSpan.FromMilliseconds(200); + var source = Observable.Timer(TimeSpan.Zero, period).Take(5); + var result = source.ToArray(); + result.Subscribe( + arr => { + Console.WriteLine("Received array"); + foreach (var value in arr) + { + Console.WriteLine(value); + } + }, + () => Console.WriteLine("Completed") + ); + Console.WriteLine("Subscribed"); + + //Subscribed + //Received array + //0 + //1 + //2 + //3 + //4 + //Completed + + } + } +} diff --git a/Examples/Examples/Chapter3/LeavingTheMonad/ToEnumerable.cs b/Examples/Examples/Chapter3/LeavingTheMonad/ToEnumerable.cs new file mode 100644 index 0000000..0a050f4 --- /dev/null +++ b/Examples/Examples/Chapter3/LeavingTheMonad/ToEnumerable.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.LeavingTheMonad +{ + class ToEnumerable + { + public void Example() + { + var period = TimeSpan.FromMilliseconds(200); + var source = Observable.Timer(TimeSpan.Zero, period) + .Take(5); + var result = source.ToEnumerable(); + foreach (var value in result) + { + Console.WriteLine(value); + } + Console.WriteLine("done"); + + //0 + //1 + //2 + //3 + //4 + //done + } + } +} diff --git a/Examples/Examples/Chapter3/LeavingTheMonad/ToEvent.cs b/Examples/Examples/Chapter3/LeavingTheMonad/ToEvent.cs new file mode 100644 index 0000000..109380d --- /dev/null +++ b/Examples/Examples/Chapter3/LeavingTheMonad/ToEvent.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.LeavingTheMonad +{ + class ToEvent + { + public void Example() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)) + .Take(5); + var result = source.ToEvent(); + result.OnNext += val => Console.WriteLine(val); + + //0 + //1 + //2 + //3 + //4 + } + + public class MyEventArgs : EventArgs + { + private readonly long _value; + public MyEventArgs(long value) + { + _value = value; + } + public long Value + { + get { return _value; } + } + } + + public void ExampleToEventPattern() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)) + .Select(i => new EventPattern(this, new MyEventArgs(i))); + var result = source.ToEventPattern(); + result.OnNext += (sender, eventArgs) => Console.WriteLine(eventArgs.Value); + + //0 + //1 + //2 + //3 + //4 + //... + } + } +} diff --git a/Examples/Examples/Chapter3/LeavingTheMonad/ToTask.cs b/Examples/Examples/Chapter3/LeavingTheMonad/ToTask.cs new file mode 100644 index 0000000..93703ef --- /dev/null +++ b/Examples/Examples/Chapter3/LeavingTheMonad/ToTask.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.LeavingTheMonad +{ + class ToTask + { + public void Example() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)) + .Take(5); + var result = source.ToTask(); //Will arrive in 5 seconds. + Console.WriteLine(result.Result); + + //4 + } + + public void ExampleOnError() + { + var source = Observable.Throw(new Exception("Fail!")); + var result = source.ToTask(); + try + { + Console.WriteLine(result.Result); + } + catch (AggregateException e) + { + Console.WriteLine(e.InnerException.Message); + } + + //Fail! + } + } +} diff --git a/Examples/Examples/Chapter3/SideEffects/AsObservable.cs b/Examples/Examples/Chapter3/SideEffects/AsObservable.cs new file mode 100644 index 0000000..41ade65 --- /dev/null +++ b/Examples/Examples/Chapter3/SideEffects/AsObservable.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.SideEffects +{ + class AsObservable + { + public class UltraLeakyLetterRepo + { + public ReplaySubject Letters { get; set; } + public UltraLeakyLetterRepo() + { + Letters = new ReplaySubject(); + Letters.OnNext("A"); + Letters.OnNext("B"); + Letters.OnNext("C"); + } + } + + public class LeakyLetterRepo + { + private readonly ReplaySubject _letters; + public LeakyLetterRepo() + { + _letters = new ReplaySubject(); + _letters.OnNext("A"); + _letters.OnNext("B"); + _letters.OnNext("C"); + } + + public ReplaySubject Letters + { + get { return _letters; } + } + } + + public class ObscuredLeakinessLetterRepo + { + private readonly ReplaySubject _letters; + public ObscuredLeakinessLetterRepo() + { + _letters = new ReplaySubject(); + _letters.OnNext("A"); + _letters.OnNext("B"); + _letters.OnNext("C"); + } + + public IObservable Letters + { + get { return _letters; } + } + } + + public class SafeLaterRepo + { + private readonly ReplaySubject _letters; + public SafeLaterRepo() + { + _letters = new ReplaySubject(); + _letters.OnNext("A"); + _letters.OnNext("B"); + _letters.OnNext("C"); + } + + public IObservable Letters + { + get { return _letters.AsObservable(); } + } + } + + public void ExampleObscuredLeakiness() + { + var repo = new ObscuredLeakinessLetterRepo(); + var good = repo.Letters; + var evil = repo.Letters; + good.Subscribe( + Console.WriteLine); + //Be naughty + var asSubject = evil as ISubject; + if (asSubject != null) + { + //So naughty, 1 is not a letter! + asSubject.OnNext("1"); + } + else + { + Console.WriteLine("could not sabotage"); + } + + //A + //B + //C + //1 + } + + public void ExampleSafe() + { + var repo = new SafeLaterRepo(); + var good = repo.Letters; + var evil = repo.Letters; + good.Subscribe( + Console.WriteLine); + //Be naughty + var asSubject = evil as ISubject; + if (asSubject != null) + { + //So naughty, 1 is not a letter! + asSubject.OnNext("1"); + } + else + { + Console.WriteLine("could not sabotage"); + } + + //A + //B + //C + //could not sabotage + + } + } +} diff --git a/Examples/Examples/Chapter3/SideEffects/Do.cs b/Examples/Examples/Chapter3/SideEffects/Do.cs new file mode 100644 index 0000000..50f3bee --- /dev/null +++ b/Examples/Examples/Chapter3/SideEffects/Do.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.SideEffects +{ + class Do + { + private static void Log(object onNextValue) + { + Console.WriteLine("Logging OnNext({0}) @ {1}", onNextValue, DateTime.Now); + } + private static void Log(Exception onErrorValue) + { + Console.WriteLine("Logging OnError({0}) @ {1}", onErrorValue, DateTime.Now); + } + private static void Log() + { + Console.WriteLine("Logging OnCompleted()@ {0}", DateTime.Now); + } + + public void Example() + { + var source = Observable + .Interval(TimeSpan.FromSeconds(1)) + .Take(3); + var result = source.Do( + i => Log(i), + ex => Log(ex), + () => Log()); + result.Subscribe( + Console.WriteLine, + () => Console.WriteLine("completed")); + + //Logging OnNext(0) @ 01/01/2012 12:00:00 + //0 + //Logging OnNext(1) @ 01/01/2012 12:00:01 + //1 + //Logging OnNext(2) @ 01/01/2012 12:00:02 + //2 + //Logging OnCompleted() @ 01/01/2012 12:00:02 + //completed + } + + private static IObservable GetNumbers() + { + return Observable.Interval(TimeSpan.FromMilliseconds(250)) + .Do(i => Console.WriteLine("pushing {0} from GetNumbers", i)); + } + + public void ExampleService() + { + var source = GetNumbers(); + var result = source.Where(i => i % 3 == 0) + .Take(3) + .Select(i => (char)(i + 65)); + result.Subscribe( + Console.WriteLine, + () => Console.WriteLine("completed")); + + //pushing 0 from GetNumbers + //A + //pushing 1 from GetNumbers + //pushing 2 from GetNumbers + //pushing 3 from GetNumbers + //D + //pushing 4 from GetNumbers + //pushing 5 from GetNumbers + //pushing 6 from GetNumbers + //G + //completed + + } + } +} diff --git a/Examples/Examples/Chapter3/SideEffects/ExternalState.cs b/Examples/Examples/Chapter3/SideEffects/ExternalState.cs new file mode 100644 index 0000000..a404bd8 --- /dev/null +++ b/Examples/Examples/Chapter3/SideEffects/ExternalState.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.SideEffects +{ + class ExternalState + { + public void ExampleWrong() + { + var letters = Observable.Range(0, 3) + .Select(i => (char)(i + 65)); + var index = -1; + var result = letters.Select( + c => + { + index++; + return c; + }); + result.Subscribe( + c => Console.WriteLine("Received {0} at index {1}", c, index), + () => Console.WriteLine("completed")); + result.Subscribe( + c => Console.WriteLine("Also received {0} at index {1}", c, index), + () => Console.WriteLine("2nd completed")); + + //Received A at index 0 + //Received B at index 1 + //Received C at index 2 + //completed + //Also received A at index 3 + //Also received B at index 4 + //Also received C at index 5 + //2nd completed + } + + public void ExampleSafe() + { + var source = Observable.Range(0, 3); + var result = source.Select( + (idx, value) => new + { + Index = idx, + Letter = (char)(value + 65) + }); + result.Subscribe( + x => Console.WriteLine("Received {0} at index {1}", x.Letter, x.Index), + () => Console.WriteLine("completed")); + result.Subscribe( + x => Console.WriteLine("Also received {0} at index {1}", x.Letter, x.Index), + () => Console.WriteLine("2nd completed")); + + //Received A at index 0 + //Received B at index 1 + //Received C at index 2 + //completed + //Also received A at index 0 + //Also received B at index 1 + //Also received C at index 2 + //2nd completed + } + } +} diff --git a/Examples/Examples/Chapter3/SideEffects/SharedState.cs b/Examples/Examples/Chapter3/SideEffects/SharedState.cs new file mode 100644 index 0000000..7fe5dc4 --- /dev/null +++ b/Examples/Examples/Chapter3/SideEffects/SharedState.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.SideEffects +{ + class SharedState + { + public class Account + { + public int Id { get; set; } + public string Name { get; set; } + } + + public void Example() + { + var source = new Subject(); + //Evil code. It modifies the Account object. + source.Subscribe(account => account.Name = "Garbage"); + //unassuming well behaved code + source.Subscribe( + account => Console.WriteLine("{0} {1}", account.Id, account.Name), + () => Console.WriteLine("completed")); + source.OnNext(new Account { Id = 1, Name = "Microsoft" }); + source.OnNext(new Account { Id = 2, Name = "Google" }); + source.OnNext(new Account { Id = 3, Name = "IBM" }); + source.OnCompleted(); + + //1 Garbage + //2 Garbage + //3 Garbage + //completed + + } + } +} diff --git a/Examples/Examples/Chapter3/TimeShifted/Buffer.cs b/Examples/Examples/Chapter3/TimeShifted/Buffer.cs new file mode 100644 index 0000000..ed72e39 --- /dev/null +++ b/Examples/Examples/Chapter3/TimeShifted/Buffer.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.TimeShifted +{ + class Buffer + { + public void ExampleByCountTime() + { + var idealBatchSize = 15; + var maxTimeDelay = TimeSpan.FromSeconds(3); + var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10) + .Concat(Observable.Interval(TimeSpan.FromSeconds(0.01)).Take(100)); + source.Buffer(maxTimeDelay, idealBatchSize) + .Subscribe( + buffer => Console.WriteLine("Buffer of {1} @ {0}", DateTime.Now, buffer.Count), + () => Console.WriteLine("Completed")); + + //Buffer of 3 @ 01/01/2012 12:00:03 + //Buffer of 3 @ 01/01/2012 12:00:06 + //Buffer of 3 @ 01/01/2012 12:00:09 + //Buffer of 15 @ 01/01/2012 12:00:10 + //Buffer of 15 @ 01/01/2012 12:00:10 + //Buffer of 15 @ 01/01/2012 12:00:10 + //Buffer of 15 @ 01/01/2012 12:00:11 + //Buffer of 15 @ 01/01/2012 12:00:11 + //Buffer of 15 @ 01/01/2012 12:00:11 + //Buffer of 11 @ 01/01/2012 12:00:11 + } + + public void ExampleOverlappingCount() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10); + source.Buffer(3, 1) + .Subscribe( + buffer => + { + Console.WriteLine("--Buffered values"); + foreach (var value in buffer) + { + Console.WriteLine(value); + } + }, () => Console.WriteLine("Completed")); + + //--Buffered values + //0 + //1 + //2 + //--Buffered values + //1 + //2 + //3 + //--Buffered values + //2 + //3 + //4 + //--Buffered values + //3 + //4 + //5 + //... + } + + public void ExampleSkippingCount() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10); + source.Buffer(3, 5) + .Subscribe( + buffer => + { + Console.WriteLine("--Buffered values"); + foreach (var value in buffer) + { + Console.WriteLine(value); + } + }, () => Console.WriteLine("Completed")); + + //--Buffered values + //0 + //1 + //2 + //--Buffered values + //5 + //6 + //7 + //Completed + } + + public void ExampleOverlappingTime() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10); + var overlapped = source.Buffer(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(1)); + overlapped.Subscribe( + buffer => + { + Console.WriteLine("--Buffered values"); + foreach (var value in buffer) + { + Console.WriteLine(value); + } + }, () => Console.WriteLine("Completed")); + + //--Buffered values + //0 + //1 + //2 + //--Buffered values + //0 + //1 + //2 + //3 + //--Buffered values + //2 + //3 + //4 + //--Buffered values + //3 + //4 + //5 + //--Buffered values + //4 + //5 + //6 + //--Buffered values + //5 + //6 + //7 + //--Buffered values + //6 + //7 + //8 + //--Buffered values + //7 + //8 + //9 + //--Buffered values + //8 + //9 + //--Buffered values + //9 + //Completed + + } + + public void ExampleSkippingTime() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10); + var skipped = source.Buffer(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5)); + skipped.Subscribe( + buffer => + { + Console.WriteLine("--Buffered values"); + foreach (var value in buffer) + { + Console.WriteLine(value); + } + }, () => Console.WriteLine("Completed")); + + //--Buffered values + //0 + //1 + //--Buffered values + //4 + //5 + //6 + //--Buffered values + //9 + //Completed + + } + + public void ExampleDynamic1() + { + Observable.Interval(TimeSpan.FromMilliseconds(100)) + .Buffer(Observable.Interval(TimeSpan.FromMilliseconds(300))) + .Subscribe(b => Console.WriteLine(String.Join(", ", b))); + + //0, 1 + //2, 3, 4 + //5, 6, 7 + //8, 9, 10 + //11, 12, 13 + //14, 15 + //16, 17, 18 + //19, 20, 21 + //22, 23, 24 + //25, 26, 27 + } + + public void ExampleDynamic2() + { + Observable.Interval(TimeSpan.FromMilliseconds(100)) + .Buffer(() => Observable.Timer(TimeSpan.FromMilliseconds(300))) + .Subscribe(b => Console.WriteLine(String.Join(", ", b))); + + //0, 1 + //2, 3, 4 + //5, 6, 7 + //8, 9, 10 + //11, 12, 13 + //14, 15 + //16, 17, 18 + //19, 20, 21 + //22, 23, 24 + //25, 26, 27 + } + + public void ExampleDynamicOverlapping() + { + Observable.Interval(TimeSpan.FromMilliseconds(100)) + .Buffer( + Observable.Timer(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)), + (v) => Observable.Timer(TimeSpan.FromMilliseconds(100 * v))) + .Subscribe(b => Console.WriteLine(String.Join(", ", b))); + + //1 + //2, 3 + //3, 4, 5 + //4, 5, 6, 7 + //5, 6, 7, 8, 9 + //... + } + } +} diff --git a/Examples/Examples/Chapter3/TimeShifted/Delay.cs b/Examples/Examples/Chapter3/TimeShifted/Delay.cs new file mode 100644 index 0000000..0c29a5e --- /dev/null +++ b/Examples/Examples/Chapter3/TimeShifted/Delay.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.TimeShifted +{ + class Delay + { + public void Example() + { + var source = Observable.Interval(TimeSpan.FromSeconds(1)) + .Take(5) + .Timestamp(); + var delay = source.Delay(TimeSpan.FromSeconds(2)); + source.Subscribe( + value => Console.WriteLine("source : {0}", value), + () => Console.WriteLine("source Completed")); + delay.Subscribe( + value => Console.WriteLine("delay : {0}", value), + () => Console.WriteLine("delay Completed")); + + //source: 0@01/01/2012 12:00:00 pm + 00:00 + //source: 1@01/01/2012 12:00:01 pm + 00:00 + //source: 2@01/01/2012 12:00:02 pm + 00:00 + //delay: 0@01/01/2012 12:00:00 pm + 00:00 + //source: 3@01/01/2012 12:00:03 pm + 00:00 + //delay: 1@01/01/2012 12:00:01 pm + 00:00 + //source: 4@01/01/2012 12:00:04 pm + 00:00 + //source Completed + //delay: 2@01/01/2012 12:00:02 pm + 00:00 + //delay: 3@01/01/2012 12:00:03 pm + 00:00 + //delay: 4@01/01/2012 12:00:04 pm + 00:00 + //delay Completed + } + } +} diff --git a/Examples/Examples/Chapter3/TimeShifted/Sample.cs b/Examples/Examples/Chapter3/TimeShifted/Sample.cs new file mode 100644 index 0000000..60c6d7e --- /dev/null +++ b/Examples/Examples/Chapter3/TimeShifted/Sample.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.TimeShifted +{ + class Sample + { + public void Example() + { + var interval = Observable.Interval(TimeSpan.FromMilliseconds(150)); + interval.Sample(TimeSpan.FromSeconds(1)) + .Subscribe(Console.WriteLine); + + //5 + //11 + //18 + } + } +} diff --git a/Examples/Examples/Chapter3/TimeShifted/Throttle.cs b/Examples/Examples/Chapter3/TimeShifted/Throttle.cs new file mode 100644 index 0000000..f58d8a7 --- /dev/null +++ b/Examples/Examples/Chapter3/TimeShifted/Throttle.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.TimeShifted +{ + class Throttle + { + // TODO make something up + } +} diff --git a/Examples/Examples/Chapter3/TimeShifted/Timeout.cs b/Examples/Examples/Chapter3/TimeShifted/Timeout.cs new file mode 100644 index 0000000..34a3d29 --- /dev/null +++ b/Examples/Examples/Chapter3/TimeShifted/Timeout.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter3.TimeShifted +{ + class Timeout + { + public void Example() + { + var source = Observable.Interval(TimeSpan.FromMilliseconds(100)).Take(5) + .Concat(Observable.Interval(TimeSpan.FromSeconds(2))); + var timeout = source.Timeout(TimeSpan.FromSeconds(1)); + timeout.Subscribe( + Console.WriteLine, + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //0 + //1 + //2 + //3 + //4 + //System.TimeoutException: The operation has timed out. + } + + public void ExampleByDate() + { + var dueDate = DateTimeOffset.UtcNow.AddSeconds(4); + var source = Observable.Interval(TimeSpan.FromSeconds(1)); + var timeout = source.Timeout(dueDate); + timeout.Subscribe( + Console.WriteLine, + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //0 + //1 + //2 + //System.TimeoutException: The operation has timed out. + } + } +} diff --git a/Examples/Examples/Chapter4/Scheduling/CreateAsync.cs b/Examples/Examples/Chapter4/Scheduling/CreateAsync.cs new file mode 100644 index 0000000..06400d1 --- /dev/null +++ b/Examples/Examples/Chapter4/Scheduling/CreateAsync.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Scheduling +{ + class CreateAsync + { + public void Example() + { + Console.WriteLine("Starting on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + Observable.Create(async o => + { + Console.WriteLine("Invoked on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + await Task.Delay(500); + o.OnNext(1); + await Task.Delay(500); + o.OnNext(2); + o.OnCompleted(); + + Console.WriteLine("Finished on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + }) + .Subscribe( + o => Console.WriteLine("Received {1} on threadId:{0}", + Thread.CurrentThread.ManagedThreadId, + o), + () => Console.WriteLine("OnCompleted on threadId:{0}", + Thread.CurrentThread.ManagedThreadId)); + Console.WriteLine("Subscribed on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + + //Starting on threadId:9 + //Invoked on threadId:9 + //Subscribed on threadId:9 + //Received 1 on threadId:11 + //Received 2 on threadId:11 + //OnCompleted on threadId:11 + //Finished on threadId:11 + } + } +} diff --git a/Examples/Examples/Chapter4/Scheduling/FileReader.cs b/Examples/Examples/Chapter4/Scheduling/FileReader.cs new file mode 100644 index 0000000..9dfb42b --- /dev/null +++ b/Examples/Examples/Chapter4/Scheduling/FileReader.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Scheduling +{ + class FileReader + { + string filename = @"test.txt"; + + public void ExampleSimple() + { + var source = new FileStream(filename, FileMode.Open, FileAccess.Read); + Func> factory = + (b, offset, bSize) => + source.ReadAsync(b, 0, bSize).ToObservable(); + var buffer = new byte[source.Length]; + IObservable reader = factory(buffer, 0, (int)source.Length); + reader.Subscribe( + bytesRead => + Console.WriteLine("Read {0} bytes from file into buffer", bytesRead)); + + //Read 19 bytes from file into buffer + } + + public void Example() + { + var source = new FileStream(filename, FileMode.Open, FileAccess.Read); + source.ToObservable(10, Scheduler.Default) + .Count() + .Subscribe( + bytesRead => + Console.WriteLine("Read {0} bytes from file", bytesRead)); + } + } + + static class FileStreamExtensions + { + private sealed class StreamReaderState + { + private readonly int _bufferSize; + private readonly Func> _factory; + public StreamReaderState(FileStream source, int bufferSize) + { + _bufferSize = bufferSize; + _factory = (b, offset, bSize) => + source.ReadAsync(b, 0, bSize).ToObservable(); + Buffer = new byte[bufferSize]; + } + public IObservable ReadNext() + { + return _factory(Buffer, 0, _bufferSize); + } + public byte[] Buffer { get; set; } + } + + public static IObservable ToObservable( + this FileStream source, + int buffersize, + IScheduler scheduler) + { + var bytes = Observable.Create(o => + { + var initialState = new StreamReaderState(source, buffersize); + var currentStateSubscription = new SerialDisposable(); + Action> iterator = + (state, self) => + currentStateSubscription.Disposable = state.ReadNext() + .Subscribe( + bytesRead => + { + for (int i = 0; i < bytesRead; i++) + { + o.OnNext(state.Buffer[i]); + } + if (bytesRead > 0) + self(state); + else + o.OnCompleted(); + }, + o.OnError); + var scheduledWork = scheduler.Schedule(initialState, iterator); + return new CompositeDisposable(currentStateSubscription, scheduledWork); + }); + return Observable.Using(() => source, _ => bytes); + } + } +} diff --git a/Examples/Examples/Chapter4/Scheduling/SchedulerAsync.cs b/Examples/Examples/Chapter4/Scheduling/SchedulerAsync.cs new file mode 100644 index 0000000..55700a3 --- /dev/null +++ b/Examples/Examples/Chapter4/Scheduling/SchedulerAsync.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Scheduling +{ + class SchedulerAsync + { + public IObservable RangeRecursive(int start, int count, IScheduler scheduler) + { + return Observable.Create(observer => + { + return scheduler.Schedule(0, (i, self) => + { + if (i < count) + { + observer.OnNext(start + i); + self(i + 1); /* Here is the recursive call */ + } + else + { + observer.OnCompleted(); + } + }); + }); + } + + public void ExampleRecursive() + { + var scheduler = Scheduler.Default; + RangeRecursive(0, 3, scheduler) + .Subscribe(i => Console.WriteLine("First " + i)); + RangeRecursive(0, 3, scheduler) + .Subscribe(i => Console.WriteLine("Second " + i)); + Console.WriteLine("Subscribed"); + + //Subscribed + //First 0 + //Second 0 + //Second 1 + //First 1 + //Second 2 + //First 2 + } + + public IObservable RangeAsync(int start, int count, IScheduler scheduler) + { + return Observable.Create(observer => + { + return scheduler.ScheduleAsync(async (ctrl, ct) => + { + for (int i = 0; i < count; i++) + { + observer.OnNext(start + i); + await ctrl.Yield(); /* Use a task continuation to schedule next event */ + } + observer.OnCompleted(); + + return Disposable.Empty; + }); + }); + } + + public void ExampleAsync() + { + var scheduler = Scheduler.Default; + RangeAsync(0, 3, scheduler) + .Subscribe(i => Console.WriteLine("First " + i)); + RangeAsync(0, 3, scheduler) + .Subscribe(i => Console.WriteLine("Second " + i)); + Console.WriteLine("Subscribed"); + + //Subscribed + //First 0 + //Second 0 + //First 1 + //Second 1 + //First 2 + //Second 2 + } + } +} diff --git a/Examples/Examples/Chapter4/Scheduling/Schedulers.cs b/Examples/Examples/Chapter4/Scheduling/Schedulers.cs new file mode 100644 index 0000000..a5e6eab --- /dev/null +++ b/Examples/Examples/Chapter4/Scheduling/Schedulers.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Scheduling +{ + class Schedulers + { + public void Example1() + { + var myName = "Lee"; + new NewThreadScheduler().Schedule( + () => Console.WriteLine("myName = {0}", myName)); + + // myName = Lee + } + + public void Example2() + { + var scheduler = Scheduler.Default; + var myName = "Lee"; + scheduler.Schedule(myName, + (_, state) => + { + Console.WriteLine(state); + return Disposable.Empty; + }); + myName = "John"; + + // Lee + } + + public void Example3() + { + var scheduler = Scheduler.Default; + var list = new List(); + scheduler.Schedule(list, + (innerScheduler, state) => + { + Console.WriteLine(state.Count); + return Disposable.Empty; + }); + list.Add(1); + + // 1 + // or (race condition) + // 0 + } + + public void ExampleFuture() + { + var scheduler = Scheduler.Default; + var delay = TimeSpan.FromSeconds(1); + Console.WriteLine("Before schedule at {0:o}", DateTime.Now); + scheduler.Schedule(delay, + () => Console.WriteLine("Inside schedule at {0:o}", DateTime.Now)); + Console.WriteLine("After schedule at {0:o}", DateTime.Now); + + //Before schedule at 2012 - 01 - 01T12: 00:00.000000 + 00:00 + //After schedule at 2012 - 01 - 01T12: 00:00.058000 + 00:00 + //Inside schedule at 2012 - 01 - 01T12: 00:01.044000 + 00:00 + } + + public void ExampleCancelation() + { + var scheduler = Scheduler.Default; + var delay = TimeSpan.FromSeconds(1); + Console.WriteLine("Before schedule at {0:o}", DateTime.Now); + var token = scheduler.Schedule(delay, + () => Console.WriteLine("Inside schedule at {0:o}", DateTime.Now)); + Console.WriteLine("After schedule at {0:o}", DateTime.Now); + token.Dispose(); + + //Before schedule at 2012 - 01 - 01T12: 00:00.000000 + 00:00 + //After schedule at 2012 - 01 - 01T12: 00:00.058000 + 00:00 + } + + public IDisposable Work(IScheduler scheduler, List list) + { + var tokenSource = new CancellationTokenSource(); + var cancelToken = tokenSource.Token; + var task = new Task(() => + { + Console.WriteLine(); + for (int i = 0; i < 1000; i++) + { + var sw = new SpinWait(); + for (int j = 0; j < 3000; j++) sw.SpinOnce(); + Console.Write("."); + list.Add(i); + if (cancelToken.IsCancellationRequested) + { + Console.WriteLine("Cancelation requested"); + //cancelToken.ThrowIfCancellationRequested(); + return; + } + } + }, cancelToken); + task.Start(); + return Disposable.Create(tokenSource.Cancel); + } + + public void ExampleCancelationToken() + { + var scheduler = Scheduler.Default; + var list = new List(); + Console.WriteLine("Enter to quit:"); + var token = scheduler.Schedule(list, Work); + Console.ReadLine(); + Console.WriteLine("Cancelling..."); + token.Dispose(); + Console.WriteLine("Cancelled"); + + //Enter to quit: + //........ + //Cancelling... + //Cancelled + //Cancelation requested + } + + public void ExampleCancellingRecursion() + { + Action work = (Action self) => + { + Console.WriteLine("Running"); + self(); + }; + var s = Scheduler.Default; + var token = s.Schedule(work); + Console.ReadLine(); + Console.WriteLine("Cancelling"); + token.Dispose(); + Console.WriteLine("Cancelled"); + + //Enter to quit: + //Running + //Running + //Running + //Running + //Cancelling + //Cancelled + //Running + } + } +} diff --git a/Examples/Examples/Chapter4/Scheduling/SchedulersInDepth.cs b/Examples/Examples/Chapter4/Scheduling/SchedulersInDepth.cs new file mode 100644 index 0000000..d10051b --- /dev/null +++ b/Examples/Examples/Chapter4/Scheduling/SchedulersInDepth.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Scheduling +{ + class SchedulersInDepth + { + private static void ScheduleTasks(IScheduler scheduler) + { + Action leafAction = () => Console.WriteLine("----leafAction."); + Action innerAction = () => + { + Console.WriteLine("--innerAction start."); + scheduler.Schedule(leafAction); + Console.WriteLine("--innerAction end."); + }; + Action outerAction = () => + { + Console.WriteLine("outer start."); + scheduler.Schedule(innerAction); + Console.WriteLine("outer end."); + }; + scheduler.Schedule(outerAction); + } + + public void ExampleCurrentThread() + { + ScheduleTasks(Scheduler.CurrentThread); + + //outer start. + //outer end. + //--innerAction start. + //--innerAction end. + //----leafAction. + } + + public void ExampleImmediate() + { + ScheduleTasks(Scheduler.Immediate); + + //outer start. + //--innerAction start. + //----leafAction. + //--innerAction end. + //outer end. + } + + private static IDisposable OuterAction(IScheduler scheduler, string state) + { + Console.WriteLine("{0} start. ThreadId:{1}", + state, + Thread.CurrentThread.ManagedThreadId); + scheduler.Schedule(state + ".inner", InnerAction); + Console.WriteLine("{0} end. ThreadId:{1}", + state, + Thread.CurrentThread.ManagedThreadId); + return Disposable.Empty; + } + private static IDisposable InnerAction(IScheduler scheduler, string state) + { + Console.WriteLine("{0} start. ThreadId:{1}", + state, + Thread.CurrentThread.ManagedThreadId); + scheduler.Schedule(state + ".Leaf", LeafAction); + Console.WriteLine("{0} end. ThreadId:{1}", + state, + Thread.CurrentThread.ManagedThreadId); + return Disposable.Empty; + } + private static IDisposable LeafAction(IScheduler scheduler, string state) + { + Console.WriteLine("{0}. ThreadId:{1}", + state, + Thread.CurrentThread.ManagedThreadId); + return Disposable.Empty; + } + + public void ExampleNewThread() + { + Console.WriteLine("Starting on thread :{0}", + Thread.CurrentThread.ManagedThreadId); + new NewThreadScheduler().Schedule("A", OuterAction); + + //Starting on thread:8 + //A start. ThreadId:9 + //A end. ThreadId:9 + //A.inner start. ThreadId:9 + //A.inner end. ThreadId:9 + //A.inner.Leaf.ThreadId:9 + } + + public void ExampleNewThreadSecondTask() + { + IScheduler scheduler = new NewThreadScheduler(); + Console.WriteLine("Starting on thread :{0}", + Thread.CurrentThread.ManagedThreadId); + scheduler.Schedule("A", OuterAction); + scheduler.Schedule("B", OuterAction); + + //Starting on thread :9 + //A start. ThreadId:10 + //A end. ThreadId:10 + //A.inner start . ThreadId:10 + //A.inner end. ThreadId:10 + //A.inner.Leaf. ThreadId:10 + //B start. ThreadId:11 + //B end. ThreadId:11 + //B.inner start . ThreadId:11 + //B.inner end. ThreadId:11 + //B.inner.Leaf. ThreadId:11 + } + + public void ExampleThreadPool() + { + Console.WriteLine("Starting on thread :{0}", + Thread.CurrentThread.ManagedThreadId); + var scheduler = ThreadPoolScheduler.Instance; + scheduler.Schedule("A", OuterAction); + scheduler.Schedule("B", OuterAction); + + //Starting on thread :9 + //A start. ThreadId:10 + //A end. ThreadId:10 + //A.inner start . ThreadId:10 + //A.inner end. ThreadId:10 + //A.inner.Leaf. ThreadId:10 + //B start. ThreadId:11 + //B end. ThreadId:11 + //B.inner start . ThreadId:10 + //B.inner end. ThreadId:10 + //B.inner.Leaf. ThreadId:11 + } + } +} diff --git a/Examples/Examples/Chapter4/Scheduling/SingleThreaded.cs b/Examples/Examples/Chapter4/Scheduling/SingleThreaded.cs new file mode 100644 index 0000000..c41c61f --- /dev/null +++ b/Examples/Examples/Chapter4/Scheduling/SingleThreaded.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Scheduling +{ + class SingleThreaded + { + public void Example() + { + Console.WriteLine("Starting on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + var subject = new Subject(); + subject.Subscribe( + o => Console.WriteLine("Received {1} on threadId:{0}", + Thread.CurrentThread.ManagedThreadId, + o)); + ParameterizedThreadStart notify = obj => + { + Console.WriteLine("OnNext({1}) on threadId:{0}", + Thread.CurrentThread.ManagedThreadId, obj); + subject.OnNext(obj); + }; + notify(1); + new Thread(notify).Start(2); + new Thread(notify).Start(3); + + //Starting on threadId:9 + //OnNext(1) on threadId:9 + //Received 1 on threadId:9 + //OnNext(2) on threadId:10 + //Received 2 on threadId:10 + //OnNext(3) on threadId:11 + //Received 3 on threadId:11 + } + } +} diff --git a/Examples/Examples/Chapter4/Scheduling/SubscribeOn.cs b/Examples/Examples/Chapter4/Scheduling/SubscribeOn.cs new file mode 100644 index 0000000..33d19f5 --- /dev/null +++ b/Examples/Examples/Chapter4/Scheduling/SubscribeOn.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Scheduling +{ + class SubscribeOn + { + public void Example() + { + Console.WriteLine("Starting on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + var source = Observable.Create( + o => + { + Console.WriteLine("Invoked on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + o.OnNext(1); + o.OnNext(2); + o.OnNext(3); + o.OnCompleted(); + Console.WriteLine("Finished on threadId:{0}", + Thread.CurrentThread.ManagedThreadId); + return Disposable.Empty; + }); + source + .SubscribeOn(Scheduler.Default) + .Subscribe( + o => Console.WriteLine("Received {1} on threadId:{0}", + Thread.CurrentThread.ManagedThreadId, + o), + () => Console.WriteLine("OnCompleted on threadId:{0}", + Thread.CurrentThread.ManagedThreadId)); + Console.WriteLine("Subscribed on threadId:{0}", Thread.CurrentThread.ManagedThreadId); + + //Starting on threadId:9 + //Subscribed on threadId:9 + //Invoked on threadId:10 + //Received 1 on threadId:10 + //Received 2 on threadId:10 + //Received 3 on threadId:10 + //OnCompleted on threadId:10 + //Finished on threadId:10 + } + } +} diff --git a/Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs b/Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs new file mode 100644 index 0000000..ec7d398 --- /dev/null +++ b/Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.SequencesOfCoincidence +{ + class GroupJoin + { + // TODO ivnent examples + } +} diff --git a/Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs b/Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs new file mode 100644 index 0000000..cea5035 --- /dev/null +++ b/Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.SequencesOfCoincidence +{ + class Join + { + // TODO invent examples + + } +} diff --git a/Examples/Examples/Chapter4/SequencesOfCoincidence/Window.cs b/Examples/Examples/Chapter4/SequencesOfCoincidence/Window.cs new file mode 100644 index 0000000..5244a49 --- /dev/null +++ b/Examples/Examples/Chapter4/SequencesOfCoincidence/Window.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.SequencesOfCoincidence +{ + class Window + { + public void Example() + { + var windowIdx = 0; + var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10); + source.Window(3) + .Subscribe(window => + { + var id = windowIdx++; + Console.WriteLine("--Starting new window"); + var windowName = "Window" + windowIdx; + window.Subscribe( + value => Console.WriteLine("{0} : {1}", windowName, value), + ex => Console.WriteLine("{0} : {1}", windowName, ex), + () => Console.WriteLine("{0} Completed", windowName)); + }, + () => Console.WriteLine("Completed")); + + //--Starting new window + //Window1 : 0 + //Window1 : 1 + //Window1 : 2 + //Window1 Completed + //--Starting new window + //Window2 : 3 + //Window2 : 4 + //Window2 : 5 + //Window2 Completed + //--Starting new window + //Window3 : 6 + //Window3 : 7 + //Window3 : 8 + //Window3 Completed + //--Starting new window + //Window4 : 9 + //Window4 Completed + //Completed + } + + public void ExampleManualClosing() + { + var windowIdx = 0; + var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10); + var closer = new Subject(); + source.Window(() => closer) + .Subscribe(window => + { + var thisWindowIdx = windowIdx++; + Console.WriteLine("--Starting new window"); + var windowName = "Window" + thisWindowIdx; + window.Subscribe( + value => Console.WriteLine("{0} : {1}", windowName, value), + ex => Console.WriteLine("{0} : {1}", windowName, ex), + () => Console.WriteLine("{0} Completed", windowName)); + }, + () => Console.WriteLine("Completed")); + var input = ""; + while (input != "exit") + { + input = Console.ReadLine(); + closer.OnNext(Unit.Default); + } + + //--Starting new window + //window0 : 0 + //window0 : 1 + //window0 Completed + //--Starting new window + //window1 : 2 + //window1 : 3 + //window1 : 4 + //window1 : 5 + //window1 Completed + //--Starting new window + //window2 : 6 + //window2 : 7 + //window2 : 8 + //window2 : 9 + //window2 Completed + //Completed + } + } +} diff --git a/Examples/Examples/Chapter4/Testing/AdvancedFeatures.cs b/Examples/Examples/Chapter4/Testing/AdvancedFeatures.cs new file mode 100644 index 0000000..ea160fe --- /dev/null +++ b/Examples/Examples/Chapter4/Testing/AdvancedFeatures.cs @@ -0,0 +1,155 @@ +using Microsoft.Reactive.Testing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive; +using System.Reactive.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples.Chapter4.Testing +{ + class AdvancedFeatures + { + public void ExampleITestableObserver() + { + var scheduler = new TestScheduler(); + var source = Observable.Interval(TimeSpan.FromSeconds(1), scheduler) + .Take(4); + var testObserver = scheduler.Start( + () => source, + 0, + 0, + TimeSpan.FromSeconds(5).Ticks); + Console.WriteLine("Time is {0} ticks", scheduler.Clock); + Console.WriteLine("Received {0} notifications", testObserver.Messages.Count); + foreach (Recorded> message in testObserver.Messages) + { + Console.WriteLine("{0} @ {1}", message.Value, message.Time); + } + + //Time is 50000000 ticks + //Received 5 notifications + //OnNext(0) @ 10000001 + //OnNext(1) @ 20000001 + //OnNext(2) @ 30000001 + //OnNext(3) @ 40000001 + //OnCompleted() @ 40000001 + } + + public void ExampleLateITestableObserver() + { + var scheduler = new TestScheduler(); + var source = Observable.Interval(TimeSpan.FromSeconds(1), scheduler) + .Take(4); + var testObserver = scheduler.Start( + () => Observable.Interval(TimeSpan.FromSeconds(1), scheduler).Take(4), + 0, + TimeSpan.FromSeconds(2).Ticks, + TimeSpan.FromSeconds(5).Ticks); + Console.WriteLine("Time is {0} ticks", scheduler.Clock); + Console.WriteLine("Received {0} notifications", testObserver.Messages.Count); + foreach (Recorded> message in testObserver.Messages) + { + Console.WriteLine("{0} @ {1}", message.Value, message.Time); + } + + //Time is 50000000 ticks + //Received 2 notifications + //OnNext(0) @ 30000000 + //OnNext(1) @ 40000000 + } + + public void ExampleCreateColdObservable() + { + var scheduler = new TestScheduler(); + var source = scheduler.CreateColdObservable( + new Recorded>(10000000, Notification.CreateOnNext(0L)), + new Recorded>(20000000, Notification.CreateOnNext(1L)), + new Recorded>(30000000, Notification.CreateOnNext(2L)), + new Recorded>(40000000, Notification.CreateOnNext(3L)), + new Recorded>(40000000, Notification.CreateOnCompleted()) + ); + var testObserver = scheduler.Start( + () => source, + 0, + 0, + TimeSpan.FromSeconds(5).Ticks); + Console.WriteLine("Time is {0} ticks", scheduler.Clock); + Console.WriteLine("Received {0} notifications", testObserver.Messages.Count); + foreach (Recorded> message in testObserver.Messages) + { + Console.WriteLine(" {0} @ {1}", message.Value, message.Time); + } + + //Time is 50000000 ticks + //Received 5 notifications + //OnNext(0) @ 10000001 + //OnNext(1) @ 20000001 + //OnNext(2) @ 30000001 + //OnNext(3) @ 40000001 + //OnCompleted() @ 40000001 + } + + public void ExampleCreateHotObservable() + { + var scheduler = new TestScheduler(); + var source = scheduler.CreateHotObservable( + new Recorded>(10000000, Notification.CreateOnNext(0L)), + new Recorded>(20000000, Notification.CreateOnNext(1L)), + new Recorded>(30000000, Notification.CreateOnNext(2L)), + new Recorded>(40000000, Notification.CreateOnNext(3L)), + new Recorded>(40000000, Notification.CreateOnCompleted()) + ); + var testObserver = scheduler.Start( + () => source, + 0, + 0, + TimeSpan.FromSeconds(5).Ticks); + Console.WriteLine("Time is {0} ticks", scheduler.Clock); + Console.WriteLine("Received {0} notifications", testObserver.Messages.Count); + foreach (Recorded> message in testObserver.Messages) + { + Console.WriteLine(" {0} @ {1}", message.Value, message.Time); + } + + //Time is 50000000 ticks + //Received 5 notifications + //OnNext(0) @ 10000000 + //OnNext(1) @ 20000000 + //OnNext(2) @ 30000000 + //OnNext(3) @ 40000000 + //OnCompleted() @ 40000000 + } + + public void ExampleCreateHotObservableLate() + { + var scheduler = new TestScheduler(); + var source = scheduler.CreateHotObservable( + new Recorded>(10000000, Notification.CreateOnNext(0L)), + new Recorded>(20000000, Notification.CreateOnNext(1L)), + new Recorded>(30000000, Notification.CreateOnNext(2L)), + new Recorded>(40000000, Notification.CreateOnNext(3L)), + new Recorded>(40000000, Notification.CreateOnCompleted()) + ); + var testObserver = scheduler.Start( + () => source, + 0, + TimeSpan.FromSeconds(1).Ticks, + TimeSpan.FromSeconds(5).Ticks); + Console.WriteLine("Time is {0} ticks", scheduler.Clock); + Console.WriteLine("Received {0} notifications", testObserver.Messages.Count); + foreach (Recorded> message in testObserver.Messages) + { + Console.WriteLine(" {0} @ {1}", message.Value, message.Time); + } + + //Time is 50000000 ticks + //Received 4 notifications + //OnNext(1) @ 20000000 + //OnNext(2) @ 30000000 + //OnNext(3) @ 40000000 + //OnCompleted() @ 40000000 + } + } +} diff --git a/Examples/Examples/Chapter4/Testing/TestSchedulerExamples.cs b/Examples/Examples/Chapter4/Testing/TestSchedulerExamples.cs new file mode 100644 index 0000000..6c77549 --- /dev/null +++ b/Examples/Examples/Chapter4/Testing/TestSchedulerExamples.cs @@ -0,0 +1,142 @@ +using Microsoft.Reactive.Testing; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Reactive.Concurrency; +using System.Reactive.Linq; + +namespace IntroToRx.Examples.Chapter4.Testing +{ + class TestSchedulerExamples + { + public void Example() + { + var scheduler = new TestScheduler(); + var wasExecuted = false; + scheduler.Schedule(() => wasExecuted = true); + Assert.IsFalse(wasExecuted); + scheduler.AdvanceBy(1); //execute 1 tick of queued actions + Assert.IsTrue(wasExecuted); + } + + public void ExampleAdvanceTo() + { + var scheduler = new TestScheduler(); + scheduler.Schedule(() => Console.WriteLine("A")); //Schedule immediately + scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B")); + scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C")); + Console.WriteLine("scheduler.AdvanceTo(1);"); + scheduler.AdvanceTo(1); + Console.WriteLine("scheduler.AdvanceTo(10);"); + scheduler.AdvanceTo(10); + Console.WriteLine("scheduler.AdvanceTo(15);"); + scheduler.AdvanceTo(15); + Console.WriteLine("scheduler.AdvanceTo(20);"); + scheduler.AdvanceTo(20); + + //scheduler.AdvanceTo(1); + //A + //scheduler.AdvanceTo(10); + //B + //scheduler.AdvanceTo(15); + //scheduler.AdvanceTo(20); + //C + } + + public void ExampleAdvanceBy() + { + var scheduler = new TestScheduler(); + scheduler.Schedule(() => Console.WriteLine("A")); //Schedule immediately + scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B")); + scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C")); + Console.WriteLine("scheduler.AdvanceBy(1);"); + scheduler.AdvanceBy(1); + Console.WriteLine("scheduler.AdvanceBy(9);"); + scheduler.AdvanceBy(9); + Console.WriteLine("scheduler.AdvanceBy(5);"); + scheduler.AdvanceBy(5); + Console.WriteLine("scheduler.AdvanceBy(5);"); + scheduler.AdvanceBy(5); + + //scheduler.AdvanceBy(1); + //A + //scheduler.AdvanceBy(9); + //B + //scheduler.AdvanceBy(5); + //scheduler.AdvanceBy(5); + //C + } + + public void ExampleStart() + { + var scheduler = new TestScheduler(); + scheduler.Schedule(() => Console.WriteLine("A")); //Schedule immediately + scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B")); + scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C")); + Console.WriteLine("scheduler.Start();"); + scheduler.Start(); + Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock); + scheduler.Schedule(() => Console.WriteLine("D")); + + //scheduler.Start(); + //A + //B + //C + //scheduler.Clock:20 + } + + public void ExampleStop() + { + var scheduler = new TestScheduler(); + scheduler.Schedule(() => Console.WriteLine("A")); + scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B")); + scheduler.Schedule(TimeSpan.FromTicks(15), scheduler.Stop); + scheduler.Schedule(TimeSpan.FromTicks(20), () => Console.WriteLine("C")); + Console.WriteLine("scheduler.Start();"); + scheduler.Start(); + Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock); + + //scheduler.Start(); + //A + //B + //scheduler.Clock:15 + } + + public void ExampleCollision() + { + var scheduler = new TestScheduler(); + scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("A")); + scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("B")); + scheduler.Schedule(TimeSpan.FromTicks(10), () => Console.WriteLine("C")); + Console.WriteLine("scheduler.Start();"); + scheduler.Start(); + Console.WriteLine("scheduler.Clock:{0}", scheduler.Clock); + + //scheduler.AdvanceTo(10); + //A + //B + //C + //scheduler.Clock:10 + } + + [TestMethod] + public void Testing_with_test_scheduler() + { + var expectedValues = new long[] { 0, 1, 2, 3, 4 }; + var actualValues = new List(); + var scheduler = new TestScheduler(); + var interval = Observable + .Interval(TimeSpan.FromSeconds(1), scheduler) + .Take(5); + interval.Subscribe(actualValues.Add); + scheduler.Start(); + CollectionAssert.AreEqual(expectedValues, actualValues); + //Executes in less than 0.01s "on my machine" + + // + } + } +} diff --git a/Examples/Examples/SampleExtensions.cs b/Examples/Examples/SampleExtensions.cs new file mode 100644 index 0000000..336cb35 --- /dev/null +++ b/Examples/Examples/SampleExtensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IntroToRx.Examples +{ + public static class SampleExtentions + { + public static void Dump(this IObservable source, string name) + { + source.Subscribe( + i => Console.WriteLine("{0}-->{1}", name, i), + ex => Console.WriteLine("{0} failed-->{1}", name, ex.Message), + () => Console.WriteLine("{0} completed", name)); + } + } +} From 059b7f9d02f5a01e915535ca68095ae41a591459 Mon Sep 17 00:00:00 2001 From: Chris Froussios Date: Mon, 6 Jul 2015 17:18:55 +0200 Subject: [PATCH 4/5] Supplemented missing examples --- .../Examples/Chapter2/Aggregation/MinMaxBy.cs | 33 ++++++++++++++++++- .../Chapter2/Creating/FromEnumerable.cs | 19 ++++++++++- .../ErrorHandling/OnErrorResumeNext.cs | 20 ++++++++++- .../Examples/Chapter3/TimeShifted/Throttle.cs | 21 +++++++++++- .../SequencesOfCoincidence/GroupJoin.cs | 33 ++++++++++++++++++- .../Chapter4/SequencesOfCoincidence/Join.cs | 32 +++++++++++++++++- 6 files changed, 152 insertions(+), 6 deletions(-) diff --git a/Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs b/Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs index 3d0d28f..be15688 100644 --- a/Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs +++ b/Examples/Examples/Chapter2/Aggregation/MinMaxBy.cs @@ -3,11 +3,42 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Reactive.Linq; namespace IntroToRx.Examples.Chapter2.Aggregation { class MinMaxBy { - // TODO invent examples + public void Example() + { + var data = new String[] + { + "First", + "Second", + "Third" + }; + var source = data.ToObservable(); + + source.MaxBy(s => s.Length) + .Subscribe(vs => + { + Console.Write("MaxBy: "); + foreach (var item in vs) + Console.Write(item + ", "); + Console.WriteLine(); + }); + + source.MinBy(s => s.Length) + .Subscribe(vs => + { + Console.Write("MinxBy: "); + foreach (var item in vs) + Console.Write(item + ", "); + Console.WriteLine(); + }); + + //MaxBy: Second, + //MinxBy: First, Third, + } } } diff --git a/Examples/Examples/Chapter2/Creating/FromEnumerable.cs b/Examples/Examples/Chapter2/Creating/FromEnumerable.cs index 92c648a..360de1c 100644 --- a/Examples/Examples/Chapter2/Creating/FromEnumerable.cs +++ b/Examples/Examples/Chapter2/Creating/FromEnumerable.cs @@ -3,11 +3,28 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Reactive.Linq; namespace IntroToRx.Examples { class FromEnumerable { - // TODO invent example + private IEnumerable MyEnumerable(int start) + { + yield return start; + yield return start + 1; + yield return start + 2; + } + + public void Example() + { + MyEnumerable(2) + .ToObservable() + .Subscribe(Console.WriteLine); + + //2 + //3 + //4 + } } } diff --git a/Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs b/Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs index 42deee5..36ef93d 100644 --- a/Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs +++ b/Examples/Examples/Chapter3/ErrorHandling/OnErrorResumeNext.cs @@ -3,11 +3,29 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Reactive.Linq; namespace IntroToRx.Examples.Chapter3.ErrorHandling { class OnErrorResumeNext { - // TODO invent examples + public void Example() + { + var source = Observable.Create(o => + { + o.OnNext(0); + o.OnNext(1); + o.OnError(new Exception("Fail")); + return () => { }; + }); + + source + .OnErrorResumeNext(Observable.Return(-1)) + .Subscribe(Console.WriteLine); + + //0 + //1 + //-1 + } } } diff --git a/Examples/Examples/Chapter3/TimeShifted/Throttle.cs b/Examples/Examples/Chapter3/TimeShifted/Throttle.cs index f58d8a7..1c73084 100644 --- a/Examples/Examples/Chapter3/TimeShifted/Throttle.cs +++ b/Examples/Examples/Chapter3/TimeShifted/Throttle.cs @@ -3,11 +3,30 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Reactive.Linq; namespace IntroToRx.Examples.Chapter3.TimeShifted { class Throttle { - // TODO make something up + public void Example() + { + var source = Observable.Concat( + Observable.Interval(TimeSpan.FromMilliseconds(200)).Take(3), + Observable.Interval(TimeSpan.FromMilliseconds(100)).Take(3), + Observable.Interval(TimeSpan.FromMilliseconds(200)).Take(3) + ) + .Select((_, i) => i); + + source.Throttle(TimeSpan.FromMilliseconds(150)) + .Subscribe(Console.WriteLine); + + //0 + //1 + //5 + //6 + //7 + //8 + } } } diff --git a/Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs b/Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs index ec7d398..0440aee 100644 --- a/Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs +++ b/Examples/Examples/Chapter4/SequencesOfCoincidence/GroupJoin.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive; +using System.Reactive.Linq; using System.Text; using System.Threading.Tasks; @@ -8,6 +10,35 @@ namespace IntroToRx.Examples.Chapter4.SequencesOfCoincidence { class GroupJoin { - // TODO ivnent examples + public void Example() + { + var left = Observable.Interval(TimeSpan.FromMilliseconds(100)) + .Take(6); + var right = Observable.Interval(TimeSpan.FromMilliseconds(200)) + .Select(i => "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[(int)i]) + .Take(3); + + Observable.GroupJoin( + left, + right, + _ => Observable.Never(), + _ => Observable.Return(Unit.Default), + (l, rs) => rs.Subscribe(r => Console.WriteLine(l + " - " + r))) + .Subscribe(); + + //0 - A + //1 - A + //0 - B + //1 - B + //2 - B + //3 - B + //0 - C + //1 - C + //2 - C + //3 - C + //4 - C + //5 - C + + } } } diff --git a/Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs b/Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs index cea5035..2ad1e20 100644 --- a/Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs +++ b/Examples/Examples/Chapter4/SequencesOfCoincidence/Join.cs @@ -3,12 +3,42 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Reactive.Linq; +using System.Reactive; +using Microsoft.Reactive.Testing; namespace IntroToRx.Examples.Chapter4.SequencesOfCoincidence { class Join { - // TODO invent examples + public void Example() + { + var left = Observable.Interval(TimeSpan.FromMilliseconds(100)); + var right = Observable.Interval(TimeSpan.FromMilliseconds(200)) + .Select(i => "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[(int)i]) + .Take(26); + Observable.Join( + left, + right, + i => Observable.Never(), + i => Observable.Return(Unit.Default), + (l, r) => l + " - " + r) + .Take(12) + .Subscribe(Console.WriteLine); + + //0 - B + //1 - B + //0 - C + //1 - C + //2 - C + //3 - C + //0 - D + //1 - D + //2 - D + //3 - D + //4 - D + //5 - D + } } } From f96fada6b8d8f83b5dfbcfff43826d42c508aad9 Mon Sep 17 00:00:00 2001 From: Chris Froussios Date: Mon, 6 Jul 2015 17:19:29 +0200 Subject: [PATCH 5/5] Better runnable examples --- .../Chapter2/Creating/SimpleFactories.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Examples/Examples/Chapter2/Creating/SimpleFactories.cs b/Examples/Examples/Chapter2/Creating/SimpleFactories.cs index c2d8cb0..2849c1a 100644 --- a/Examples/Examples/Chapter2/Creating/SimpleFactories.cs +++ b/Examples/Examples/Chapter2/Creating/SimpleFactories.cs @@ -10,51 +10,51 @@ namespace IntroToRx.Examples { class SimpleFactories { - //TODO: improve format - public void ExampleReturn() { var singleValue = Observable.Return("Value"); - //which could have also been simulated with a replay subject - var subject = new ReplaySubject(); - subject.OnNext("Value"); - subject.OnCompleted(); - singleValue.Subscribe(Console.WriteLine); - + singleValue.Subscribe( + Console.WriteLine, + Console.WriteLine, + () => Console.WriteLine("Completed")); + //Value + //Completed } public void ExampleEmpty() { var empty = Observable.Empty(); - //Behaviorally equivalent to - var subject = new ReplaySubject(); - subject.OnCompleted(); - empty.Subscribe(Console.WriteLine); + empty.Subscribe( + Console.WriteLine, + Console.WriteLine, + () => Console.WriteLine("Completed")); + + //Completed } public void ExampleNever() { var never = Observable.Never(); - //similar to a subject without notifications - var subject = new Subject(); - never.Subscribe(Console.WriteLine); + never.Subscribe( + Console.WriteLine, + Console.WriteLine, + () => Console.WriteLine("Completed")); + + // } public void ExampleThrow() { var throws = Observable.Throw(new Exception()); - //Behaviorally equivalent to - var subject = new ReplaySubject(); - subject.OnError(new Exception()); throws.Subscribe( Console.WriteLine, Console.WriteLine, - Console.WriteLine); + () => Console.WriteLine("Completed")); //System.Exception: Exception of type 'System.Exception' was thrown. }