Pergunta

.NET 4.0 beta 2 tem introduziu IObservable e IObserver interfaces.

Quais são as vantagens em relação aos eventos clássicos .NET? Isso não resolver o mesmo problema?

Foi útil?

Solução

Você pode usar IObservable como um evento, substituindo código que expõe eventos com propriedades do tipo IObservable, mas isso não é realmente o ponto.

Há duas coisas importantes para entender sobre IObservable:

  1. Ele unifica dois conceitos que não sabíamos como unificar antes :. Operações assíncronas (que normalmente retornam um único valor) e eventos (que normalmente vão para sempre)

  2. É combináveis ??. Ao contrário de eventos CLR, IAsyncResult, ou INotifyCollectionChanged permite-nos eventos de construção específicas para fora dos acontecimentos gerais e operações assíncronas.

Aqui está um exemplo ran I em pelo trabalho apenas esta tarde.

No Silverlight existem alguns efeitos que você pode aplicar a um controle de imagem que não pode ser aplicado a um controle normal. Para contornar essas limitações quando o conteúdo de um controle é alterado posso esperar por sua aparência visual a ser atualizado e ter uma imagem dele. Então eu quero esconder sua representação visual, substituí-lo com o instantâneo, e aplicar os efeitos visuais para a imagem. Agora eu posso aplicar efeitos de imagem a um controle (assumindo que não é interativo).

Este programa seria trivial, mas pelo fato de que ele deve ser assíncrona. Devo esperar por duas operações assíncronas consecutivos para completar antes que eu possa aplicar efeitos para a imagem:

  1. O conteúdo do controle é alterado
  2. aparência visual do controle é atualizado

Aqui está como eu resolver este problema utilizando 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);
   }
}

Este exemplo é particularmente simples dado que há apenas duas operações consecutivas para sequência. Mesmo nesse exemplo simples, porém, podemos ver que Rx agrega valor. Sem ele eu teria de ter estado variáveis ??usados ??para garantir os eventos estavam disparando em uma determinada ordem. Eu também teria tido de escrever algum código muito feio para separar explicitamente a partir do evento LayoutUpdated.

Quando você estiver programação com Rx o truque é pensar "O evento que eu gostaria que minha estrutura fornecida?" e depois ir para criá-lo. Somos treinados para pensar sobre eventos tão simples, as coisas orientado a entrada ( "mouseover", "clique de mouse", "keyup", etc). No entanto, há nenhum evento a razão não pode ser muito complexo e específico para seu aplicativo ( "GoogleMsdnMashupStockDataArrived", "DragStarting", e "ImageContentChanged"). Quando você estruturar seus programas desta forma (criar exatamente a necessidade evento I e depois responder a ela, mudando de estado), você vai achar que eles têm menos bugs do Estado, tornam-se mais ordenada, e são completamente mais auto -describing.

Entendeu? :-)

Outras dicas

Eu não tenho certeza das vantagens, mas eu vejo as seguintes diferenças com eventos clássicos NET:

notificações Erro

eventos clássicos exigiria um evento separado para isso, ou uma classe EventArgs com uma propriedade Error que precisa ser verificado.

notificação de fim de notificações

eventos clássicos exigiria um evento separado para este ou uma classe EventArgs com uma propriedade Final que precisa ser verificado.

É apenas uma extensão do modelo de programação baseada em eventos. Você criar algo que implementa IObserver, e, basicamente, você está dizendo "aqui está o que eu quero que aconteça quando algo nas mudanças de cobrança". Dessa forma, é apenas uma padronização do que todos nós temos vindo a fazer com os eventos.

Eles estão empurrando-o como se fosse uma grande reviravolta em comparação com o padrão de IEnumerable. IEnumerable é "puxar", enquanto IObservable é "push".

A única vantagem que eu vejo mais eventos retas é que é uma interface padronizada. Eu vejo uma grande sobreposição com ObservableCollection aqui embora (e INotifyCollectionChanged). Talvez estejam tentando adotar o lema PERL com .NET:. "Há mais de uma maneira de fazê-lo"

Você deve definitivamente assistir Rx Workshop: observáveis ??contra Eventos vídeo completar o Desafio anexado

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top