Desenvolvimento - C#
.NET Reactive Framework
A Microsoft trabalha atualmente em um projeto chamado de .NET Reactive Framework (Rx).
por Israel AéceQuando dizemos que teremos uma outra forma de trabalhar depois deste framework, é porque ele permitirá o que chamamos de LINQ To Events. Isso quer dizer que poderemos, de forma declarativa, definir uma sequência/combinação de eventos que estamos interessados, e quando ele(s) acontecer(em), nós seremos notificados. Antes de visualizar códigos que mostram isso, vamos recapitular como o Linq To Objects trabalha: basicamente tudo é baseado nas interfaces IEnumerable<T> e IEnumerator<T>, que utilizam o conceito de "pull" (puxar) para extrair os dados, iterando por alguma fonte de dados de forma síncrona.
Erik Meijer, que é o inventor do Rx Framework, descobriu que toda sequência que trabalha no formato "pull", também pode trabalhar no formato "push" (empurrar), ou seja, são matematicamente denominadas como "Dual".Para suportar a programação reativa, não podemos continuar utilizando as mesmas interfaces, justamente porque elas bloqueiam até que um próximo resultado esteja disponível. Sendo assim, a Microsoft introduziu duas novas interfaces: IObservable<T> e IObserver<T>. Através destas interfaces, você assinará uma coleção/tarefa qualquer, e quando uma nova informação estiver disponível, você será notificado, reagindo à este item.
Já vi comentários que isso será parte integrante ao .NET Framework 4.0, mas os tipos necessários para fazer isso tudo funcionar, estão contidos no assembly System.Reactive.dll, que vem com o Toolkit do Silverlight3.0. A primeira interface, IObservable<T>, possui apenas um método chamado Subscribe. Este método recebe como parâmetro a instância de uma classe que implementa a interface IObserver<T>, que possui três métodos autoexplicativos: OnCompleted, OnError e OnNext. Em um exemplo simples, vamos percorrer uma coleção de números inteiros através desta nova forma. O primeiro passo é criar o observer:
public class VerificadorDeItens : IObserver<int>
{
public void OnCompleted()
{
Console.WriteLine("Acabou");
}
public void OnError(Exception exception)
{
Console.WriteLine("Erro");
}
public void OnNext(int value)
{
Console.WriteLine(value);
}
}
Depois dele devidamente criado, precisamos criar o "observable". Ao invés de fazermos isso explicitamente, a Microsoft também disponibilizou uma classe chamada Observable, que está dentro namespace System.Linq. Essa classe fornece uma série de métodos de extensão, para transformar grande parte dos operadores LINQ em "observables". Um desses métodos, ToObservable, é responsável por transformar um IEnumerable<T> em um IObservable<T>. Sendo assim, para percorrer um array de números inteirosno formato"push", fazemos:
int[] ids = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ids.ToObservable().Subscribe(new VerificadorDeItens());
O que vimos acima, é somente um exemplo da diferença entre os modelos "pull" e "push", mas o mais interessante é a capacidade de manipular, ou melhor, de reagirà eventos. Ao invés de criar os tratadores (event handlers) tradicionais, você poderá "assinar" esse evento, e quando ele acontecer, você será notificado. Veja o exemplo abaixo:
Observable
.FromEvent<EventArgs>(this.button1, "Click")
.Subscribe(() => MessageBox.Show("Ocorreu o evento Click"));
Um ponto importante aqui é que o método Subscribe retorna a instância de uma classe que implementa a interface IDisposable, que poderá ser utilizada mais tarde, quando não quisermos mais ser notificados. Abaixo temos o mesmo exemplo, só que se descartando as notificações quando não precisamos mais delas, e para isso, tudo o que precisamos fazer é invocar o método Dispose:
IDisposable dispose =
Observable
.FromEvent<EventArgs>(this.button1, "Click")
.Subscribe(() => MessageBox.Show("Ocorreu o evento Click"));
//faz algo aqui, e quando não estiver mais
//interessado nas notificações, invoque o
//método Dispose.
dispose.Dispose();
Tudo isso visa, principalmente, a capacidade que teremos que efetuar queries LINQ em eventos, que como falei acima, permite vincular à eventos, e na medida com que eles forem sendo disparados, você será notificado de forma assíncrona. Para isso, vamos imaginar que temos duas classes diferentes, onde cada uma delas possui um evento específico, e um método que executa alguma tarefa, e quando necessário, invoca o respectivo evento. Abaixo temos as duas classes que utilizaremos como exemplo. Repare que não há nada de especial:
public class Classe1
{
public event EventHandler MeuEvento;
public void Executar()
{
if (this.MeuEvento != null)
this.MeuEvento(this, EventArgs.Empty);
}
}
public class Classe2
{
public event EventHandler MeuOutroEvento;
public void Executar()
{
if (this.MeuOutroEvento != null)
this.MeuOutroEvento(this, EventArgs.Empty);
}
}
Com essas classes criadas, vamos então utilizar o LINQ para interagir com os eventos:
Classe1 c1 = new Classe1();
Classe2 c2 = new Classe2();
IObservable<Event<EventArgs>> obsC1 =
Observable.FromEvent<EventArgs>(c1, "MeuEvento");
IObservable<Event<EventArgs>> obsC2 =
Observable.FromEvent<EventArgs>(c2, "MeuOutroEvento");
varq =
from xin obsC1
from y in obsC2
select new Unit();
q.Subscribe(() => MessageBox.Show("Os eventos aconteceram!"));
c1.Executar();
c2.Executar();
Depois de instanciado a classe, utilizamos o método FromEvent, que dado o objeto e o nome do evento, cria um "observable" para o evento especificado. Com eles criados, o próximo passo é escrever a query LINQ, onde aninharemos os dois eventos na mesma query. Assim como toda query LINQ To Objects retorna um IEnumerable<T>, LINQ To Events retorna um IObservable<T>. Com isso, podemos utilizar o método Subscribe, para sermos notificados quando ambos eventos acontecerem. Assim que código executa o método "Executar" de "c1" e "c2",a mensagem será exibida. Se comentarmos qualquer um dos métodos "Executar", a mensagem não será disparada, pois de acordo coma query, nós estamos interessados em sermos notificados somente quando ambos eventos acontecerem.
Além de tudo isso, o .NET Reactive Framework ainda facilita muito a programação assíncrona. Sempre quando precisamos executar alguma tarefa em uma thread isolada, precisamos criar delegates, iniciar a tarefa através do método BeginInvoke, apontar (também via delegate) para o método de callback e, finalmente,recuperar o resultadoutilizando o métodoEndInvoke. Isso é extremamente trabalhoso, e a complexidade aumenta ainda mais quando não se conhece exatamente como isso funciona. Suponhamos que temos a seguinte tarefa ser realizada:
public int Tarefa(int tempo)
{
//Tarefa Custosa
tempo = tempo * 1000;
Thread.Sleep(tempo);
return tempo;
}
Ao invés de criar toda aquela parafernalha para invocar e receber o resultado assincronamente, utilizando este novo framework, tudo o que precisamos fazer é:
new Func<int, int>(Tarefa)
.ToAsync()
.Invoke(3)
.Subscribe((tempo) => { MessageBox.Show("Tempo Esperado: " + tempo.ToString()); });
No código acima, instanciamos o delegate Func<TResult, T> (que é bem conhecido), especificando que ele receberá e retornará um número inteiro. A partir daí, entra em cena o método de extensão chamado ToAsync (que foi aplicado aos delegates), que retorna uma versão assíncrona do mesmodelegate, e como já vimos acima,utilizamos o método Subscriber para criar o "observable", que nos trará o resultado do processo, isso quando estamos interessados nele.
Esses são apenas alguns - pequenos - exemplos de alguns cenários que podemos utilizar esta novo framework, mas já podemos notar o quanto ganhamos em certas situações, como é o caso da programação assíncrona. Há muito ainda o que se explorar e, provavelmente, isso tende a evoluir cada vezmais, tornando assim, a programação, ou melhor, o C#, cada vez mais funcional.