int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (int number in numbers)
{
if (number % 2 == 0) Console.WriteLine(number);
}
Este código é perfeitamente válido para as versões 1.1 e 2.0 do Framework .NET e cumpre a tarefa proposta. Mas vamos tentar mudar um pouco o foco procedural e iterativo do código acima para algo mais declarativo. O que isso quer dizer? Teria alguma forma de tormarmos mais clara a intenção desse nosso código? Vamos explorar um método introduzino na classe Array no .NET 2.0 chamado ForEach<T>.
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Array.ForEach
(
numbers,
delegate(int number)
{
if (number % 2 == 0) Console.WriteLine(number);
}
);
O método Array.ForEach<T>() é um método genérico estático que pode ser usado em arrays de qualquer tipo. Veja como a assinatura deste método está definida na classe System.Array:
public static void ForEach<T>(T[] array, Action<T> action);
O tipo Action<T>, no segundo parâmetro, é um delegate definido da seguinte forma:
public delegate void Action<T>(T obj);
O método ForEach iterage por todos os elementos do array passado e, para cada elemento, chama o método referenciado pelo delegate passando o elemento como argumento para este método. Simplificando, o método referenciado pelo delegate será chamado para cada item do array.
No nosso exemplo, o delegate é definido anonimamente, ou seja, não foi criado um método separado para esta finalidade. O código a ser executado foi simplesmente passado para a operação ForEach. Este recurso, chamado Anonymous Delegates, foi introduzido no .NET 2.0 e é um dos grandes habilitadores do design do Linq, como veremos em posts futuros.
Embora o recurso de anonymous delegates seja extremantente intessante, o código acima parece ter ficado muito mais obscuro do que o código que utilizava o loop foreach tradicional. Por conta disso, vamos dar um passo à frente e verificar como este código poderia ser escrito usando o recurso de linguagem de consulta integrada (Linq – Language Integrated Query), que será incorporado ao C# 3.0 e ao VB 9:
int[] numeros = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
IEnumerable<int> numerosPares = from numero in numeros
where numero % 2 == 0
select numero;
foreach (int par in numerosPares)
{
Console.WriteLine(par);
}
Embora tenhamos escrito mais linhas do que no código original, a semântica de manipulação de conjuntos proporcionada pela query Linq deixa claro que estamos consultando os números pares de um conjunto original (array numbers). O resultado da query é mantido em uma variável do tipo do tipo IEnumerable<int> denominada numerosPares. Para escrever esses números no console, simplesmente usamos uma construção foreach tradicional.
O código acima pode ser digitado em qualquer projeto que utilize um dos templates de projeto do LINQ Preview. Na realidade, o código é dependente do assembly System.Query.dll, que é referenciado automaticamente quando usamos um desses templates.
Gostaria de fazer um pequeno exercício de compreensão que, acredito, possa ser esclarecedor de algumas das motivações do Linq. Então, vamos à questão: como você faria para escrever no console todos os números pares existentes em um array de inteiros qualquer?
Acredito que a resposta mais básica e simplória para essa questão – embora claramente válida – é a utilização de um loop for (ou foreach) que iteraja por todos os elementos do array, teste cada um deles para verificar se é par e, caso positivo, escreva-o no console. O código abaixo mostra como isso pode ser feito:
