Вопрос

.NET 4.0 beta 2 имеет представил IObservable < Интерфейсы / a> и IObserver .

Каковы преимущества по сравнению с классическими событиями .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 добавляет ценность. Без этого мне пришлось бы использовать переменные состояния, чтобы события запускались в определенном порядке. Я также должен был бы написать довольно уродливый код для отсоединения explicity от события LayoutUpdated.

    Когда вы программируете с помощью Rx, уловка заключается в том, чтобы подумать: «Какое событие я хотел бы предоставить моей платформе?» а затем иди создать его. Мы обучены думать о событиях как о простых, управляемых вводом вещах («mouseover», «mouseclick», «quot; keyup» и т. Д.). Однако нет причин, по которым события не могут быть очень сложными и специфичными для вашего приложения (" GoogleMsdnMashupStockDataArrived " ;, " DragStarting " и " ImageContentChanged "). Когда вы структурируете свои программы таким образом (создаете именно то, что мне нужно, , а затем отвечаете на него, изменяя состояние), вы обнаружите, что у них меньше ошибок состояния, они становятся более упорядоченными и в целом более самостоятельными. -describing.

    Понял? :-)

    Другие советы

    Я не уверен в преимуществах, но вижу следующие отличия от классических событий .NET:

    уведомления об ошибках

    Классические события потребовали бы отдельного события для этого или класса EventArgs со свойством Ошибка , которое необходимо проверить.

    уведомление об окончании уведомлений

    Классические события потребовали бы отдельного события для этого или класса EventArgs со свойством Final , которое необходимо проверить.

    Это просто расширение модели программирования, основанной на событиях. Вы создаете что-то, что реализует IObserver, и в основном вы говорите: «Вот что я хочу, чтобы что-то изменилось в коллекции». Таким образом, это просто стандартизация того, что мы все делаем с событиями.

    Они настаивают на том, что это большое лицо по сравнению с шаблоном IEnumerable. IEnumerable - это "pull", тогда как IObservable - это "push".

    Единственное преимущество, которое я вижу перед прямыми событиями, это то, что это стандартизированный интерфейс. Я вижу большое перекрытие с ObservableCollection здесь, хотя (и INotifyCollectionChanged). Может быть, они пытаются перенять девиз PERL с помощью .NET: «Есть несколько способов сделать это».

    Обязательно посмотрите Семинар по Rx: наблюдаемые и события видео и завершите прилагаемый вызов

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top