Share via


Reactive Extensions (Rx) 现已开源

[原文发表地址]  Reactive Extensions (Rx) is now Open Source

[原文发表时间] November 6, 2012 9:24 PM

上次我和Erik Meijer一起制作有关.Net Reactive Extensions(Rx)的播客已有好几年了。从那个时候起,成千上万的人开始尽情在项目中使用Rx,并且很多开源项目如ReactiveUI(也可以在播客上看到)出现了。甚至Windows适用的GitHub也使用了Reactive Extensions。实际上,GitHub在Windows产品中大量使用了Rx。我在GitHub的一位朋友Paul说他非常喜欢这个模式,他们研发了一个Mac版本!

Windows适用的GitHub几乎对所有事情都使用Reactive Extensions ,包括网络请求, UI事件,子进程管理( git.exe )。通过使用Rx和ReactiveUI ,我们已经编写了一个快速,几乎100% 异步,响应迅速的应用,同时还有100% 确定,可靠的单元测试。 GitHub的桌面开发人员非常爱Rx ,甚至Mac团队创建了他们自己的Rx和ReactiveUI版本,被称为ReactiveCocoa ,现在已经在Mac使用,以获得类似的好处。

—— Paul Betts GitHub

今天,微软开源技术宣布Reactive Extensions开源的消息!你可以从https://rx.codeplex.com在Codeplex上使用git获取代码。你将无法抗拒这趟开源列车!祝贺这个伟大的团队!

这里包含了许多东西,因此热情已被点燃!这不仅有Rx.Net,还有C++库,以及JavaScript的RxJS!现在每个人都可以使用IObservable<T>和IObServer<T>玩弄它。

  • Reactive Extensions:
    • Rx.Net:Reactive Extensions(Rx)是一个实现异步和基于事件的程序的库,它使用了可察觉的序列和LINQ样式的查询运算符。
    • RxJS:JavaScript的Reactive Extensions(RxJS)是一个在JavaScript中实现异步和基于事件的程序的库,它使用了可察觉的序列和LINQ样式的查询运算符,它可以用于浏览器和Node.js。
    • Rx++:Native的 Reactive Extensions(RxC)是一个在C和C++中实现异步和基于事件的程序的库,它使用了可察觉的序列和LINQ样式的查询运算符。
  • Interactive Extensions
    • Ix:Interactive Extensions(Ix)是一个.Net库,它扩展LINQ to Object,提供许多在Rx可用的操作符,但是面向IEnumerable<T>。
    • IxJS:JavaScript中的LINQ to Object开发和Interactive Extensions (Ix)
    • Ix++:C++中供Native开发人员使用LINQ

一个学习有关为什么Rx有用的很好的方法是点击Rx Koan的工程或者阅读介绍Rx的在线电子书

为什么我认为Rx很重要?它是一个在事件流上实现异步操作的方式。而不是连接点击事件和用事件处理程序管理所有事件的状态,你可以有效地用LINQ查询一个事件的无限流。你可以声明式的排序事件……不用标记,没有状态机。

例如,这里用鼠标按键和鼠标移动事件创建了一个拖拽事件(已设计好):

 IObservable<Event<MouseEventArgs>> draggingEvent =
      from mouseLeftDownEvent in control.GetMouseLeftDown()
      from mouseMoveEvent in control.GetMouseMove().Until(control.GetMouseLeftUp())
      select mouseMoveEvent;

更胜一筹的是,Rx让它更容易(或者更可能)地创建基于事件的异步测试,像来自Jafar Husain的此

 Rating rating = new Rating();
 IObservable<Unit> test =                             // Unit is an object that represents null.
     ObservableExtensions
         .DoAsync(() => TestPanel.Children.Add(rating))
         .WaitFor(TestPanel.GetLayoutUpdated())     // Extension method GetLayoutUpdated converts the event to observable        
         .DoAsync(() => rating.Value = 1.0)        // Calls the Ignite EnqueueCallback method        
         .WaitFor(                                 // waits for an observable to raise before going on
             // listen to all the actual value change events and filters them until ActualValue reaches Value            
             rating                                      
             .GetActualValueChanged()        // extension method that converts ActualValueChanged event to IObservable
             .SkipWhile(actualValueChangedEvent => actualValueChangedEvent.EventArgs.NewValue != rating.Value))
         // check to make sure the actual value of the rating item is set appropriately now that the animation has completed
         .Assert(() => rating.GetRatingItems().Last().ActualValue == 1.0) // crawls the expression tree and makes a call to the appropriate Assert method
  
  Test.Subscribe(() => TestPanel.Children.Remove(rating));    //run the test and clean up at the end.

这是一个很棒的时间相关的操作,让你随着时间移动模拟事件。注意Buffer和Subscribe的调用

 var myInbox = EndlessBarrageOfEmail().ToObservable();
  
  // Instead of making you wait 5 minutes, we will just check every three seconds instead. :)
 var getMailEveryThreeSeconds = myInbox.Buffer(TimeSpan.FromSeconds(3)); //  Was .BufferWithTime(... 
  
 getMailEveryThreeSeconds.Subscribe(emails =>
 {
     Console.WriteLine("You've got {0} new messages!  Here they are!", emails.Count());
     foreach (var email in emails)
     {
         Console.WriteLine("> {0}", email);
     }
     Console.WriteLine();
 });

你可以使用await和async就像这个例子一样,在5秒后返回数字42:

 static async void button_Click()
 {
     int x =  await Observable.Return(42).Delay(TimeSpan.FromSeconds(5));
     // x with value 42 is returned after 5 seconds
     label.Text = x.ToString();
 }

我在这里只是为您展示了我所喜欢的部分,但是一个人也可以轻松地在大学讲上10周有关Rx的课程,但我还只是一个初学者。

这里有更多Rx资源,请点击查看。祝贺这个伟大的团队在开源方面做出的贡献!