Iterações com Yield e IEnumerable

Olá mancebos.

Hoje falarei sobre a instrução return yield e a interface IEnumerable<T> em C#, e como ambos, se usados juntos, podem melhorar a performance de iterações em listas, além de deixar o código mais limpo e bem estruturado.

Primeiramente, o que exatamente é o yield?
Bom, com certeza seu nome não é muito intuitivo. Mas, basicamente, ele é usado em junção com o return de um método (yield return) e ele mantêm o estado do método. Ou seja, todas as variáveis estarão com os mesmos valores, os objetos estarão com as mesmas referências de quando foi chamado anteriormente. Mas isso apenas em nível de iteração (será explicado mais a frente).

Parece útil? Sim. Pode-se utilizar isso em qualquer método? Não.

É aí que entra o IEnumerable. Para utilizar o yield em um método, é necessário que o mesmo tenha o retorno de IEnumerable<T>. Por quê? IEnumerable é a interface base que oferece suporte a iterações básicas, e quando declaramos o retorno do métodos com yield, estamos dizendo ao C# que nosso método será iterável.

Vejamos um exemplo de um métodos utilizando yieldIEnumerable:

public IEnumerable<int> NumerosNaturais()
{
    var numero = 0;

    while(true)
    {
        yield return numero++;
    }
}

Neste exemplo, estão presentes os elementos a quais comentei anteriormente, o tipo de retorno do método com IEnumerable<int> e a palavra-chave yield junto com return. Mas por quewhile(true)? Bem, como disse anteriormente, a utilização do IEnumerable torna o método iterável, o que significa que ele deve se comportar desse maneira. Vejamos como utilizar esse método:

foreach(var numero in NumerosNaturais())
{
    if (numero == 10) 
        break;

    Console.WriteLine("Número " + numero);
}

//Retorno: "Número 0", "Número 1", ..., "Número 9"

Simples, não? É este caso a que me referi antes. O yield mantêm o estado do método apenas por iteração. Enquanto a execução estiver no foreach, a variável numero do método NumerosNaturais vai ser continuamente incrementada, isso até a iteração parar, neste caso, até o número 9. Isso acontece porque a cada execução do foreach, a execução irá continuar do último yield return encontrado.

Essa é a vantagem do yield IEnumerable. Eu não tenho, em nenhum lugar, um registro dos números naturais, não criei nem inicializei nenhuma lista contendo-os. É possível carregar e utilizar apenas a quantidade necessária de registros.

Mas o quão prático é um if dentro do loop, apenas para delimitar a quantidade de registros? Muito pouco, com certeza. Neste caso, podemos pedir ajuda aos métodos LINQ, já que no final de contas, o nosso método retorna um IEnumerable:

foreach(var numero in NumerosNaturais().Take(10))
{
    Console.WriteLine("Número " + numero);
}

//Retorno: "Número 0", "Número 1", ..., "Número 9"

Dessa forma, temos um código que executará da mesma maneira do anterior, mas bem mais elegante, e com total suporte do LINQ. Poderíamos também, por exemplo, usar os 5 primeiros números múltiplos de 10:

foreach(var numero in NumerosNaturais().Select(n => n % 10 == 0).Take(5))
{
    Console.WriteLine("Número " + numero);
}

//Retorno: "Número 0", "Número 10", ..., "Número 40"

Conhecendo o Node.js #2

Olá novamente bípedes.

Continuando a série(!?) de posts sobre Node.js, falarei hoje sobre os parâmetros enviados por URLs e como utilizá-los no javascript. Será um post curto e simples, mas possivelmente útil.

Muito bem, como vimos no post anterior, o Node.js utilizao o CommonJS para separar e modularizar seus arquivos de forma organizada. Portanto, para termos acesso aos métodos de tratamento de URLs, devemos incluir o módulo ‘url’:

var url = require("url");

Com o módulo url em mãos, podemos utilizar seus métodos para recuperar os parâmetros da URL:

var params = url.parse(urlString, true).query;

Aqui, o método parse transforma os TODA a URL em um objeto. Neste exemplo, ele recebe dois parâmetros:

  1. A própria URL em forma de string;
  2. Um boolean que define se os parâmetro e valores da URL serão mostrados no objetos que o método irá retornar.

O método parse retorna um objeto que tem atributos como path, rost, port e claro, os parâmetros da URL(se o segundo parâmetro for true). Um exemplo do objeto:

{ 
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?Numero=5&Nome=Jean',
  query: { Numero: '5', Nome: 'Jean' },
  pathname: '/',
  path: '/?Numero=5&Nome=Jean',
  href: '/?Numero=5&Nome=Jean' 
}

Como só precisamos dos parâmetros passados pela URL nesse momento, requisitamos apenas o atributos query do objeto retornado. Assim, temos todos os parâmetros em um objeto, facilmente manipulável:

var nome = params.Nome;
var numero = params.Numero;

É importante lembrar que tudo isso é case-sensitive. Se eu chamar localhost/?NumBeR=5, o atributo no javascript será o mesmo ou seja, params.NumBeR.

Dito tudo isso, aqui vai um exemplo simples de tudo mencionado acima:

var http = require("http");
var url = require("url");

http.createServer(function (request, response)
{
    response.writeHead(200, { "Content-Type": "text/plain" });

    var params = url.parse(request.url, true).query;
    var nome = params.Nome;

    response.write("May the force be with you, " + nome);

    response.end();
}).listen(80);

console.log("Rodando...");

Conhecendo o Node.js

Bom dia, boa tarde e boa noite pequenos gafanhotos.

Hoje falarei o básico do básico do Node.js. Quem é ele? Para que serve? Onde vive? Do que se alimenta?

Node.js é uma plataforma utilizada para criar aplicações server-side de alta escalabilidade. Ele é capaz de gerir um grande número de requisições simultaneamente como um servidor web, em uma única máquina física. E o mais incrível disso tudo, programando em Javascript! Exato, javascript para o back-end. Node.js utiliza o interpretador V8 de javascript do Chrome para executar todas as suas gambiarras códigos no servidor também.

Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

Podemos começar com uma aplicação simples, então? Criaremos um web server. Primeiro, baixe o Node.js e instale-o aqui. É só seguir as instruções no instalador, extremamente simples:

Imagem

Após a instalação, podemos criar nosso primeiro script para rodar no Node.js. Vamos utilzar o exemplo do próprio site do Node como exemplo:

//Precisaremos do módulo http para esse webserver, então devemos incluí-lo
var http = require('http');

http.createServer(function (req, res) {

  //No Node, precisamos definir o header manualmente de acordo com o tipo de dados que deseja transmitir
  res.writeHead(200, { 'Content-Type': 'text/plain' });

  //Escrevendo o retorno
  res.write("Hello World!");

  //A conexão deve ser fechada manualmente
  res.end();

}).listen(1337, '127.0.0.1');

console.log('Server running at http://127.0.0.1:1337/');

O Node.js utiliza o CommonJS como sistema de modularização. Isso evita o caos que geralmente acontece ao desenvolver com javascript em vários arquivos. Portanto, devemos utilizar o método require para cada novo módulo que necessitarmos. Neste caso, como é um simples web server, utilizaremos apenas o ‘http’.

Salve esse arquivo como hello.js. Após isso, acesse o diretório onde o arquivo está salvo via cmd, e use o comando node hello.js:

Imagem

Com o servidor rodando, acesse a URL indicada no Hello.js (localhost:1337) pelo navegador, e as palavras mágicas devem aparecer:

Imagem

É bom lembrar que enquanto o servidor Node estiver rodando, o cmd vai estar ‘travado’. Para fechar o servidor, pressione CTRL + C.

WebSockets com HTML5 e Fleck

Bom dia, boa tarde e boa noite jovens. Hoje criaremos um servidor WebSocket e um cliente para consumi-lo, utilizando HTML5 no cliente e C# com a biblioteca Fleck no servidor.

Mas afinal, o que é um WebSocket? Segundo a nossa duvidosa Wikipédia portuguesa:

WebSocket é uma tecnologia que permite a comunicação bidirecional por canais full-duplex sobre um único soquete Transmission Control Protocol(TCP). Ele é projetado para ser executado em browsers e servidores web que suportem o HTML5, mas pode ser usado por qualquer cliente ou servidor de aplicativos.

A tecnologia WebSocket permite criar um único canal de comunicação entre o Cliente e Servidor, e permite o Servidor mandar requisições para o cliente, e não apenas o inverso, como ocorre normalmente.

Vamos começar criando o servidor WebSocket. Estarei utilizando o Visual Studio 2012 para isso, mas irá funcionar perfeitamente no 2010. Primeiramente, vamos criar um projeto Console Application.

Criando o Projeto

Agora, para criar o servidor WebSocket, utilizarei o Fleck, biblioteca que implementa para nós o WebSocket. Ele pode ser baixado via Nuget, ou digitando o comando Install-Package Fleck no Package Manager Console.

O Fleck é bem simples e objetivo. O que precisamos fazer é implementar os métodos onOpen, onClose e onMessage do servidor.

websocketserver

Ao criar o objeto webSocket, é preciso defiinir a URL do serviço. Também criamos uma lista de Sockets, para armazenarmos todos os clients. No método onStart, incluimos o Socket que acabou de conectar na lista e no onClose retiramos ele. No método onMessage, inserimos a rotina que será executada ao recebermos uma requisição. Neste caso, ao receber uma mensagem, mandamos a mensagem com seu conteúdo para todos os clients conectados.

Agora, na parte Client:webSocketClient

Aqui, temos os mesmo métodos onOpen, onClose e onMessage. Criamos a conexão com o servidor no momento que instanciamos o WebSocket. Observe que a URL passada como parâmetro é a mesma na URL com que criamos o servidor WebSocket.

Com tudo pronto, já podemos testar nosso servidor e client. Para isso, é preciso executar o projeto do servidor WebSocket para então acessarmos nossa página HTML. O resultado:

resultado

Importante ressaltar que o client deve estar hospedado em um servidor. Se for executado localmente, a conexão não ocorrerá.

Projeto utilizado neste post se encontra no GitHub.