Reactive Extensions for .Net .Net .Net 5.0 Rx.Net Observable Collections
Monday, May 29, 2017
   

Latest Posts

Posted on 7/28/2016 by André Pires in Reflexões
Posted on 1/10/2014 by André Pires in .Net
Posted on 1/7/2014 by André Pires

Posts

Hands-on Reactive Extensions for .Net

Posted on 11/23/2012 by André Pires in .Net
image

Vou iniciar hoje uma série de posts relacionados às novidades e/ou coisas legais do .Net Framework. Pretendo fazer no formato hands-on, propondo exercícios que abordem os assuntos. O primeiro assunto será o Rx .Net, ou Reactive Extensions. O Rx, além de ser um exame médico diagnóstico muito comum :), pode ser descrito como uma biblioteca para desenvolvimento de software assíncrono e/ou event-based através do uso de coleções observáveis. Este post é praticamente uma tradução do Beginners Guide do Rx. Eu gostei do que vi e vou compartilhar com vocês, em pt-BR, colocando pontualmente a minha visão sobre o assunto. Quem não quiser esperar os meus posts e quiser avançar nos estudos, basta procurar por Reactive Extensions for .Net no Google, ops! No Bing! :)

Introdução

Este hands-on tem como objetivo, familiarizar o leitor com o Rx. Vou usar uma série de exercícios incrementais para que o estudante sinta o poder composicional da biclioteca que pode ser usado para desenvolver aplicações assíncronas, baseando-se no conceito de Coleções Observáveis.

Pré-requisitos

Para estes exercícios, vamos assumir que os leitores já tenham os pré-requisitos intelectuais e materiais abaixo:

  • Experiência com o .Net Framework
  • Experiência com a linguagem C#
  • Conhecimento sobre os conceitos de programação assíncrona e suas complexidades
  • O Visual Studio 2010 e o .Net 4 instalados
  • A biblioteca do Rx for .Net (abaixo direi como instalar)

O que é o Rx?

É basicamente uma biblioteca, que será oficialmente parte do .Net 5.0, quando este for lançado (ao menos é isso que dizem os rumores) e que dá ao desenvolvedor ferramentas sofisticadas para a criação de aplicações assíncronas, baseadas ou não em eventos. A parte mais legal mesmo são as tais Coleções Observáveis, e meu foco será nisso.

Ela é dividia em 3 propriedades núcleo, e nós veremos cada uma delas nesses hands-on. São elas:

  • Modelos Assíncronos e Modelos Event-based - Como o nome já diz, a missão do Rx é simplificar esses modelos de programação. Quem aqui nunca se irritou com telas travadas, tanto em Windows Forms quanto em Web Forms? Com a chegada do "Mundo das Nuvens", a programação assíncrona se torna ainda mais importante e essencial. Tecnologias de baixo nível, como os eventos do .Net, os padrões assíncronos, tarefas, AJAX, etc, são geralmente assuntos complicados...
  • Composição - Combinar computação assíncrona hoje em dia é algo muito difícil. Geralmente isto envolve a criação de um monte de código que tem pouco (ou nada) a ver com o problema que queremos resolver. Em particular, o fluxo de dados de operações que está envolvido no problema não é suficientemente claro e o código se espalha através de event handlers, procedimentos assíncronos e suas callbacks, etc...
  • Coleções Observáveis - Se tentarmos ver os procedimentos em computação assíncrona como se fossem data sources, podemos obter o conhecimento atual do modelo de programação do LINQ. Já parou para pensar que o seu mouse pode ser visto como uma base de dados de movimentos e cliques? Pois é... É disso que estamos falando... No maravilhoso mundo novo proposto pelo Rx, poderemos fazer coisas como filtros, projeções, joins, operações agendadas, etc, com o teu mouse! :)

Como obter o Rx?

A forma mais fácil (e legal) é usar o NuGet Package Manager

Se você ainda não usa o NuGet, você está perdendo tempo e o prazer de conhecer uma linda ferramenta.

Ou seja, se você não usa, baixe o add-in utilizando o meu Extension Manager do seu Visual Studio. Na tela de pesquisa, vá para a Galeria Online e procure por NuGet.

Baixe e instale. Você não vai se arrepender... Quem quiser saber mais sobre o NuGet e suas utilizades, clique aqui.

Com o NuGet Instalado, poderemos então iniciar nosso exercício 1.

Exercício 1 - Familiarizando-se com as Interfaces e Assemblies do Rx.

  1. Criar uma Console Application: Abra o Visual Studio, vá para o menu File, New, Project. Entre os templates, escolha Visual C#, Windows e Console Application. Certifique-se que o .Net Framework 4 esteja selecionado no dropdown de versões do framework.

  2. Instalar o Rx com o NuGet: Vá para o menu Tools, Library Package Manager, escolha o item Package Manager Console. Isso vai abrir o "painel do NuGet". Nele, digite o seguinte comando:

    install-Package Rx-Main

    Após alguns instantes você receberá uma mensagem de instalação bem sucedida ou um erro :)
    No segundo caso, tente novamente e se não conseguir, não me perturbe! :)

  3. Quando tudo estiver instalado, você poderá ver as referências automaticamente inseridas em teu projeto, na pasta de References.

  4. Antes de começar a utilizar o biblioteca, precisamos entender como algumas coisas funcionam. Vamos iniciar com um estudo sobre duas interfaces: IObservable<T> e IObserver<T>. Ambas possuem um papel fundamental dentro do Rx e do conceito de programação assíncrona. A IObservable<T> age como uma fonte de dados que pode ser observada. Isso significa que ela pode enviar dados para qualquer indivíduo ou elemento que esteja interessado nesses dados. Esses elementos, por sua vez, são representados pela interface IObserver<T>. Então temos o Observador e o Observável, correto? Como isso funciona? Como qualquer coisa na vida que tenha esses dois elementos... Para que algo seja observado, deverá sempre existir alguém observando. No Rx isso se dá por intermédio de uma Assinatura. Todo objeto observável (que implementa IObservable<T>), terá um método chamado Subscribe. A definição das duas interfaces e de seus métodos está abaixo:

    public interface IObservable<out T>
    {
        IDisposable Subscribe(IObserver<T> observer);
    }
     
    public interface IObserver<in T>
    {
        void OnCompleted();
        void OnError(Exception error);
        void OnNext(T value);
    }

    Como você pode ver, método Subscribe da interface IObservable<T> retorna um IDisposable e que pede um parâmetro do tipo IObserver<T>. Para que o objeto observador A receba mensagens de um objeto observável B, este deverá fazer uma assinatura em B, utilizando o método Subscribe. O objeto retornado pelo método (IDisposable) servirá como um Handler para a assinatura. Isso significa que basta uma chamada ao método Dispose() do observador A para cancelar a assinatura. Não é legal? :) Apesar da semelhança com os operadores += e -= dos eventos do .Net, essa forma de trabalhar se mostrará muito mais flexível do que a forma tradicional com eventos, como veremos em breve...

  5. Ao invés de implementar essas interfaces agora, vamos ver como criar sequências observáveis utilizando ferramentas básicas da biblioteca:
    Abra a classe Program.cs do teu projeto e dentro do método Main, digite o seguinte código:

    IObservable<int> observavel;
    IObserver<int> observador;
     
    IDisposable assinatura = observavel.Subscribe(observador);
    Console.WriteLine("Pressione ENTER para cancelar a assinatura...");
    Console.ReadLine();
     
    assinatura.Dispose();

    EU SEI QUE ESSE CÓDIGO NÃO FUNCIONA!!! Não é isso que está em questão nesse momento, confie em mim...

    A biblioteca oferece UM MONTE de sequências observáveis úteis e também UM MONTE de novos operadores que podemos aplicar nessas sequências afim de compô-las.
    Se você verificar o método Subscribe(), notará que ele possui overloads e também que ele é um método de extensão. Uma de suas sobrecargas permite que você use métodos anônimos, como as LINDAS lambda expressions para tratar os 3 métodos do nosso objeto IObserver<T>, que são OnNext(), OnError() e OnCompleted()...
    Vejam os nomes e tentem imaginar o que esses métodos fazem...
    Como eu disse, eles são métodos da interface IObserver<T>, e como os nomes dizem eles podem ser usados como handlers da seguinte forma:

    OnNext: Usado para realizar tarefas quando o observador recebe uma mensagem do observável.
    OnError: Usado para realizar tarefas quando o observador recebe uma exception do observável.
    OnCompleted: Usado para realizar tarefas quando o observável não tem mais mensagens para enviar ao observador.

    Vamos ver isso em código?

    IDisposable assinatura = observavel.Subscribe(
        x => Console.WriteLine("Recebi {0} do observável.", x),
        ex => Console.WriteLine("Recebi o erro {0} do observável.", ex.Message),
        () => Console.WriteLine("O observável disse que não há mais mensagens...")
    );

    Notem que ao invés de eu passar o observador como parâmetro do método Subscribe(), eu usei 3 lambda expressions para "tratar" as 3 funcionalidades de nossa interface IObserver<T>.
    Observe também que o objeto observável fornece os métodos de extensão do LINQ, que podem ser usado para aplicar operadores nesse tipo de coleção:

Conclusão: As interfaces IObservable<T> e IObserver<T> representam objetos observáveis e observadores, respectivamente. Para observar uma sequência de dados, devemos fazer uma assinatura usando o método Subscribe() e receber um objeto IDisposable como retorno, que nos serve como um handler para a assinatura criada. Vimos também que podemos usar os métodos de extensão do LINQ em objetos observáveis, o que nos permite aplicar operadores de consulta nesses tipos de objeto. LINDO!

No próximo post (provavelmente Domingo) faremos o exercício 2 do Rx.

Abraço a todos!

WSC_CommentIt

WSC_CommentIt

Home   |   Forum
André Pires 2011