Exemplo n.º 1
0
        static void Bridges()
        {
            var evt = new MyEvents();

            //
            // Rx doesn't claim to substitue existing technologies with some new
            // approach using IObservable exclusively. For example, regular .NET
            // events, the asynchronous pattern, etc. are still perfectly fine to
            // be used. However, when composition enters the picture, Rx provides
            // a solution. Therefore we can bridge the old world to the new world
            // using various operators. Rx is the glue that binds those worlds
            // together using operators and combinators.
            //

            //
            // A first sample is FromEvent for which we have a reflective version
            // as well as one that uses add/remove handler delegates.
            //
            Console.WriteLine("FromEvent");
            var mme1 = Observable.FromEvent<MyEventArgs>(evt, "Bar");
            var mme2 = Observable.FromEvent<MyEventArgs>(handler => evt.Bar += handler, handler => evt.Bar -= handler);

            using (mme1.Subscribe(e => Console.WriteLine("1 --> " + e.EventArgs.Value)))
            using (mme2.Subscribe(e => Console.WriteLine("2 --> " + e.EventArgs.Value)))
            {
                evt.Raise(42);
                evt.Raise(43);
            }

            evt.Raise(24); // All subscriptions gone; no output expected.
            Console.WriteLine();

            //
            // Secondly, there's the asynchronous invocation Begin/End pair pattern,
            // which can be bridged using FromAsyncPattern.
            //
            Console.WriteLine("FromAsyncPattern");
            using (var fs = File.OpenRead(@"..\..\Program.cs"))
            {
                //
                // The signature of the Begin method is reflected in the FromAsyncPattern
                // generic parameters. The last one is the return type, in this case an
                // int returning the number of bytes read, as seen on the End method.
                //
                var readAsync = Observable.FromAsyncPattern<byte[], int, int, int>(fs.BeginRead, fs.EndRead);

                //
                // Using readAsync, we can invoke the Begin/End pair without worrying about
                // the IAsyncResult madness. In here, res will be an IObservable<int> which
                // will contain the result of the EndRead call, i.e. the number of bytes
                // read from the input.
                //
                var data = new byte[16];
                var res = readAsync(data, 0, data.Length);

                //
                // We'll use Run to go synchronously here, such that we don't dispose the
                // opened FileStream prematurely.
                //
                res.Run(x => Console.WriteLine("{0} bytes read: {1}", x, Encoding.ASCII.GetString(data)));
            }
            Console.WriteLine();

            //
            // Third, the Task Parallel Library introduced in .NET 4 (and backported to 3.5
            // when installing Rx) has the notion of a Task<T> which is like a single-result
            // IObservable<T> (i.e. a deferred Return<T> observable). We can convert this to
            // an observable as well.
            //
            Console.WriteLine("Task<T>");
            var tsk = Task<int>.Factory.StartNew(() => { Thread.Sleep(2000); return 42; });
            tsk.ToObservable().Run(Console.WriteLine);
            Console.WriteLine();

            //
            // Fourth, enumerable sequences can be iterated asynchronously, resulting in an
            // observable sequence as well. Let's create some sequence that ticks at a slow
            // pace, producing values 0..9, and watch it using observables. Instead of using
            // Run which would make the whole thing synchronous, we're printing dots on the
            // main thread till completion is signaled by the enumeration that's happening
            // on a background thread spawn by ToObservable. This illustrates how concurrency
            // is introduced by ToObservable.
            //
            Console.WriteLine("ToObservable");
            var xs = Enumerable.Range(0, 10).Select(x => { Thread.Sleep(x * 100); return x; });
            var isDone = false;
            xs.ToObservable(Scheduler.ThreadPool /* where to do the iteration */)
              .Subscribe(Console.WriteLine, () => isDone = true);
            while (!isDone)
            {
                Console.Write(".");
                Thread.Sleep(500);
            }
            Console.WriteLine();

            //
            // Finally, regular functions or actions can be invoked in the background as well,
            // exposing their results through an IObservable using the Start operator.
            //
            Console.WriteLine("Func");
            var anw = Observable.Start(() => { Thread.Sleep(2000); return 42; });
            anw.Run(Console.WriteLine);
            Console.WriteLine();
        }