Reactive Extensions (Rx) Explained Presenter: Kevin Grossnicklaus August 5th, 2011 Agenda • • • • Introductions Talk Additional Resources Conclusion Introductions • Kevin Grossnicklaus – ArchitectNow- www.architectnow.net (2009-Present) • President – Washington University - CAIT Program (2003-2010) • Instructor – SSE - www.SSEinc.com (1999-2009) • Chief Architect • Software Development Practice Leader • Email: kvgros@architectnow.net • Twitter: @kvgros • Blog: blog.architectnow.net EXPECTATIONS Expectations • Experience with .NET development – Samples will be in C# 4.0 – VS 2010 will be used • Basic familiarity with LINQ and some Async programming • Lambda Expressions will be used INTRODUCTION TO RX IEnumerable/IEnumerator interface IEnumerable<T> { IEnumerator<T> GetEnumerator(); } interface IEnumerator<T> : IDisposable { bool MoveNext(); T Current { get; } void Reset(); } Iterating Collections var items = new string[] { “Hello”, “World” }; foreach (var x in items) { //interact with each piece of data } //we can now assume we are done //we must also handle exceptions IObservable/IObserver interface IObservable<out T> { IDisposable Subscribe(IObserver<T> observer); } interface { void void void } IObserver<in T> OnNext(T value); OnError(Exception ex); OnCompleted(); IObservable/IObserver var _data = new string[] { "Hello", "World" }; var _observable = _data.ToObservable(); var _observer = _observable.Subscribe(x => Console.WriteLine(x)); var _observer2 = _observable.Subscribe( x => Console.WriteLine(x), () => Console.WriteLine("Completed")); var _observer3 = _observable.Subscribe( x => Console.WriteLine(x), ex => Console.WriteLine("Exception: " + ex.Message), () => Console.WriteLine("Completed")); _observer2.Dispose(); Getting Rx Installed • NuGet – Easiest and quickest • Rx Home Page: – http://msdn.microsoft.com/en-us/data/gg577609 • Simply add a reference to: – System.Reactive.DLL • Available for: – – – – – Full Framework (WPF, WinForms, server side ASP.NET, MVC, etc) Silverlight 3 and 4 JavaScript Windows 7 Phone Xbox/XNA OBSERVABLE EXTENSIONS Subjects using System.Reactive.Subjects; var _subject = new Subject<string>(); var _observer = _subject.Subscribe(x => Console.WriteLine(x)); _subject.OnNext("Rx"); _subject.OnNext("will"); _subject.OnNext("save"); _subject.OnNext("me"); _subject.OnNext("some"); _subject.OnNext("headaches"); _subject.OnCompleted(); _observer.Dispose(); Subscribing public static class ObservableExtensions { public static IDisposable Subscribe<TSource>(this IObservable<TSource> source); public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext); public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext, Action<Exception> onError); public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext, Action onCompleted); public static IDisposable Subscribe<TSource>(this IObservable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted); } Creation of Observables //simply call OnComplete var empty = Observable.Empty<string>(); //Call OnNext(“Value”) and then call OnComplete var obReturn = Observable.Return("Value"); //Raise no events var never = Observable.Never<string>(); //Call OnException with the specified expection var throws = Observable.Throw<string>(new Exception()); //Specify a delegate to be called when anyone subscribes var createSample = Observable.Create<string>( observable => { observable.OnNext("a"); observable.OnNext("b"); observable.OnCompleted(); return () => Console.WriteLine("Observer has unsubscribed"); }); Creation of Observables (Cont…) //Create a range of numbers var range = Observable.Range(10, 15); //publish a count from 0 every specified time period var interval = Observable.Interval(TimeSpan.FromMilliseconds(250)); //Never call “Next” but call “Complete” when the long running operation is done var longOperation = Observable.Start( x => ..do something that takes awhile.. ); //Generate a collection much like for (i=5, i<15, i+3) return i.ToString(); var generated = Observable.Generate(5, i => i < 15, i => i.ToString(), i => i + 3); //simply convert an existing collection or array (IEnumerable) to IObservable var converted = MyCollection.ToObservable(); Rx LINQ Operators • Where • Select • First • • • • • • • • • • FirstOrDefault Last LastOrDefault Single Count Min Max Sum Where GroupBy • • • • • • • • • • • Take TakeUntil Skip DistinctUntilChanged Buffer Throttle Sample Delay Until TimeOut ..etc…etc…etc… RX AND .NET EVENTS The “Old Way” txtSample.TextChanged += new TextChangedEventHandler(txtSample_TextChanged); //txtSample.TextChanged = new TextChangedEventHandler(txtSample_TextChanged); private string _lastValue = string.Empty; void txtSample_TextChanged(object sender, TextChangedEventArgs e) { var _currentValue = ((TextBox)sender).Text; if (_currentValue.Length > 5 && _currentValue != _lastValue) { _lastValue = _currentValue; lstData.Items.Add(_currentValue); } } The “New Way” var _textChanged = Observable .FromEventPattern<EventArgs>(txtSample, "TextChanged") .Select(x => ((TextBox)x.Sender).Text); var _longText = _textChanged .Where(x => x.Length > 5) .DistinctUntilChanged() .Throttle(TimeSpan.FromSeconds(.5)); _longText .ObserveOnDispatcher() .Subscribe(x => lstData.Items.Add(x)); ADDITIONAL TOPICS Additional Topics • Threading – Scheduler • Async Pattern • Attaching/Detaching • When should I use Rx? FINAL THOUGHTS Additional Resources • Rx Homepage – http://msdn.microsoft.com/en-us/devlabs/gg577609 • Rx Beginners Guide (Tutorials, Videos, etc) – http://msdn.microsoft.com/en-us/devlabs/gg577611 • Great Keynote Overview – http://channel9.msdn.com/posts/DC2010T0100-Keynote-Rx-curing-your-asynchronousprogramming-blues • Team Blog – http://blogs.msdn.com/b/rxteam/ • Community Rx Wiki – http://rxwiki.wikidot.com/ • Channel 9 Videos – http://channel9.msdn.com/tags/Rx/ • RxSandbox – http://mnajder.blogspot.com/2010/03/rxsandbox-v1.html • Great Blog Series by Lee Campbell – http://leecampbell.blogspot.com/2010/08/reactive-extensions-for-net.html Next Steps… kvgros@architectnow.net Twitter: @kvgros