.net - .NET Rx 相对于经典事件的优势?

标签 .net events system.reactive reactive-programming

.NET 4.0 beta 2introduced IObservableIObserver接口(interface)。

与经典 .NET 事件相比有哪些优势?这不是解决同样的问题吗?

最佳答案

您可以将 IObservable 用作事件,将暴露事件的代码替换为 IObservable 类型的属性,但这并不是重点。

关于 IObservable,有两件重要的事情需要理解:

  • 它统一了我们之前不知道如何统一的两个概念 :异步操作(通常返回单个值)和事件(通常永远持续下去)。
  • 可组合 .与 CLR 事件、IAsyncResult 或 INotifyCollectionChanged 不同,它允许我们从一般事件和异步操作中构建特定事件。

  • 这是我今天下午在工作中遇到的一个例子。

    在 Silverlight 中,您可以将某些效果应用于无法应用于普通控件的图像控件。为了在控件的内容发生更改时绕过这些限制,我可以等待其视觉外观更新并对其进行截图。然后我想隐藏它的视觉表示,用快照替换它,并将视觉效果应用到图像上。现在我可以将图像效果应用于控件(假设它不是交互式的)。

    这个程序将是微不足道的,但它必须是异步的。在我可以对图像应用效果之前,我必须等待两个连续的异步操作完成:
  • 控件内容发生变化
  • 控件的视觉外观更新

  • 以下是我使用 Rx 解决此问题的方法:
    // A content control is a control that displays content.  That content can be
    // anything at all like a string or another control.  Every content control contains
    // another control: a ContentPresenter.  The ContentPresenter's job is to generate
    // a visual representation of the Content property. For example, if the Content property
    // of the ContentControl is a string, the ContentPresenter creates a TextBlock and inserts
    // the string into it.  On the other hand if the Content property is another control the 
    // ContentPresenter just inserts it into the visual tree directly.
    public class MyContentControl : ContentControl
    {
       // A subject implements both IObservable and IObserver.  When IObserver methods
       // are called, it forwards those calls to all of its listeners.
       // As a result it has roughly the same semantics as an event that we can "raise."
       private Subject<object> contentChanged = new Subject<object>();
    
       // This is a reference to the ContentPresenter in the ContentControl's template
       private ContentPresenter contentPresenter; 
    
       // This is a reference to the Image control within ContentControl's template.  It is displayed on top of the ContentPresenter and has a cool blur effect applied to it.
       private Image contentImageControl; 
    
       public MyContentControl()
       {
          // Using Rx we can create specific events from general events.
          // In this case I want to create a specific event ("contentImageChanged") which
          // gives me exactly the data I need to respond and update the UI.
          var contentImageChanged = 
             // get the content from the content changed event
             from content in contentChanged
             where content != null
             // Wait for the ContentPresenter's visual representation to update.
             // ContentPresenter is data bound to the Content property, so it will
             // update momentarily.
             from _ in contentPresenter.GetLayoutUpdated().Take(1)
             select new WritableBitmap(contentPresenter, new TranslateTransform());
    
          contentImageChanged.Subscribe(
             contentImage => 
             {
                // Hide the content presenter now that we've taken a screen shot              
                contentPresenter.Visibility = Visibility.Collapsed; 
    
                // Set the image source of the image control to the snapshot
                contentImageControl.ImageSource = contentImage;
             });
       }
    
       // This method is invoked when the Content property is changed.
       protected override OnContentChanged(object oldContent, object newContent)
       {
          // show the content presenter before taking screenshot
          contentPresenter.Visibility = Visibility.Visible;  
    
          // raise the content changed "event"
          contentChanged.OnNext(newContent);   
    
          base.OnContentChanged(oldContent, newContent);
       }
    }
    

    这个例子特别简单,因为只有两个连续的操作要排序。即使在这个简单的示例中,我们也可以看到 Rx 增加了值(value)。如果没有它,我将不得不使用状态变量来确保事件按特定顺序触发。我还必须编写一些非常丑陋的代码来明确地从 LayoutUpdated 事件中分离出来。

    当你使用 Rx 编程时,诀窍是思考“我希望我的框架提供什么事件?”然后去创建它。我们被训练将事件视为简单的、输入驱动的事物(“mouseover”、“mouseclick”、“keyup”等)。但是,事件没有理由不能非常复杂且特定于您的应用程序(“GoogleMsdnMashupStockDataArrived”、“DragStarting”和“ImageContentChanged”)。当您以这种方式构建程序时(准确地创建我需要的事件 ,然后 通过更改状态来响应它),您会发现它们的状态错误更少,变得更有条理,并且更加自我描述。

    知道了? :-)

    关于.net - .NET Rx 相对于经典事件的优势?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1212536/

    相关文章:

    .net - 我们可以在 MySQL 中动态创建表吗?

    c# - 如何让 BinaryFormatter 在不同的应用程序中反序列化

    加载事件后的 VB.NET .NET?

    .net - 检查 WMI ManagementObject 查询是否为 Nothing 而不是使用 Try/Catch?

    c# - CoInternetSetFeatureEnabled 与 FEATURE_BLOCK_INPUT_PROMPTS 不起作用

    events - ItemInvoked 与 SelectionChanged

    c# - Excel 自动化 : Close event missing

    c# - ReactiveExtensions 和异步服务方法?

    c# - 我可以使用响应式(Reactive)扩展来对 Windows 服务的调用进行排队吗?

    c# - 在 react 性管道中执行TPL代码并通过测试计划程序控制执行