LINQ - Usando ToDictionary() e ToList() - I
Hoje veremos a utilização dos métodos de extensão ToDictionary() e ToList() da LINQ. |
Existem dois métodos de extensão LINQ simples que podem simplificar a tarefa de converter consultas de coleção em coleções. São os métodos ToDictionary() e ToList().
Se você é
desenvolvedor .NET com certeza já conhece os recursos e vantagens da
LINQ como
linguagem de consulta para obter e filtrar dados de várias fontes de dados. Os operadores
de consulta padrão são os métodos que formam o padrão da
Language-Integrated Query (LINQ).
A maioria destes métodos operam em seqüências, onde uma seqüência é um objeto
cujo tipo implementa a interface IEnumerable<T> ou a interface
IQueryable<T>.
Neste artigo vamos focar nos métodos de extensão
ToDictionary() e ToList() mas antes vamos recordar um conceito importante
que é a deferred execution ou execução adiada.
Para saber mais sobre deferred execution leia o meu artigo: LINQ - Entendendo Deferred Execution
LINQ - Deferred Execution e ToList()
Vamos iniciar criando um pequeno exemplo em um projeto Console onde vamos criar a classe Produto:
public class Produto
{
public int Id { get; set; }
public string Nome { get; set; }
public string Categoria { get; set; }
}
|
Criamos uma classe POCO anêmica que vamos usar no exemplo.
A seguir vamos criar uma coleção de objetos Produto para termos uma fonte de dados com que trabalhar criando o método estático GetProdutos() na classe Produto:
public static List<Produto> GetProdutos()
{
var produtos = new List<Produto>
{
new Produto { Nome = "CD Player", Id = 1, Categoria = "Eletrônicos" },
new Produto { Nome = "DVD Player", Id = 2, Categoria = "Eletrônicos" },
new Produto { Nome = "Blu-Ray Player", Id = 3, Categoria = "Eletrônicos" },
new Produto { Nome = "TV LCD", Id = 4, Categoria = "Eletrônicos" },
new Produto { Nome = "Pneu 175 aro 14", Id = 5, Categoria = "Automotivos" },
new Produto { Nome = "TV LED", Id = 6, Categoria = "Eletrônicos" },
new Produto { Nome = "Forno Microondas", Id = 7, Categoria = "Eletrodomésticos" },
new Produto { Nome = "Volante em couro", Id = 8, Categoria = "Automotivos" },
new Produto { Nome = "TV Plasma", Id = 9, Categoria = "Eletrônicos" },
new Produto { Nome = "Geladeira 440 L", Id = 10, Categoria = "Eletrodomésticos" },
new Produto { Nome = "Forno 4 bocas", Id = 11, Categoria = "Eletrodomésticos" },
new Produto { Nome = "Secadora", Id = 12, Categoria = "Eletrodomésticos" },
};
return produtos;
}
|
Então, digamos que você tenha uma coleção desses objetos Produto e precise consultá-los.
Por exemplo, poderíamos obter uma enumeração de todas as instâncias de Produto em que a Categoria é igual à “Eletrônicos”:
Isso pode ser feito usando a seguinte consulta : Produto.GetProdutos().Where(p => p.Categoria == "Electrônicos");
expressa no código a seguir:
static void Main(string[] args)
{
var produtosEletronicos = Produto.GetProdutos().Where(p => p.Categoria == "Electrônicos");
foreach(var produto in produtosEletronicos)
{
Console.WriteLine(produto.Nome);
}
Console.ReadLine();
}
|
Vamos colocar um breakpoint no foreach e executar o código e a seguir vamos examinar o conteúdo de produtosEletronicos:
Observe que produtosEletronicos é um IEnumerable<Produto> e não um List<Produto>.
O que esta acontecendo aqui é o que chamamos de deferred execution ou execução adiada.
O resultado de muitos dos métodos de extensão como Where() é criar um iterador que executa a consulta conforme você a move pela lista.
Portanto, neste ponto produtosEletronicos não é um List<Produto>, mas simplesmente um IEnumerable<Produto> que será avaliado em tempo real conforme você avança pela lista.
Essa é a tal execução adiada, que é um recurso do LINQ, que adia a execução não avaliando a expressão até que você precise do resultado. Assim aqui produtosEletronicos está à espera que façamos alguma coisa com ela para que nos possa dar os resultados da lista.
Assim a exibição vai ocorrer no laço foreach quando iterarmos sobre a lista.
Podemos obter o mesmo resultado obtendo a lista de produtos da seguinte forma:
1- Usando o método AddRange
var
resultado2 = new List<Produto>();
resultado2.AddRange(produtosEletronicos);
2- Usar o construtor de List que usa um IEnumerable<T>
var resultado3 = new List<Produto>(produtosEletronicos);
ExibeProdutos(resultado3);
Mas uma forma mais simples é usar o método de extensão ToList() da LINQ que vai pegar qualquer IEnumerable<T> e vai usá-lo para preencher um List<T>.
Isso é útil se você deseja executar uma consulta e usá-la para preencher uma lista em uma única etapa:
var produtosEletronicos = Produto.GetProdutos().Where(p => p.Categoria == "Eletrônicos").ToList();
Agora, em vez de
produtosEletronicos
ser um IEnumerable<T>
executado dinamicamente sobre a coleção original, será uma coleção separada e as
modificações na coleção original não a afetarão.
Isso tem vantagens e desvantagens.
Como regra geral, se você for apenas iterar os resultados e processá-los, não precisa (nem quer) armazená-lo em uma lista separada, pois isso apenas desperdiça memória que mais tarde precisará ser coletada como lixo.
No entanto, se você deseja salvar esse subconjunto e atribuí-lo a outra classe, usar o ToList() é muito útil para que você não precise se preocupar com alterações na coleção original.
Assim ToList() pega um IEnumerable<T> e o converte para um List<T>.
Na próxima parte do artigo vamos tratar com ToDictionary().
Pegue o projeto completo aqui : Linq_ToListToDictionary.zip
"Mas, se o
nosso evangelho ainda está encoberto, é para os que se perdem que está
encoberto, nos quais o deus deste século cegou o entendimento dos incrédulos,
para que lhes não resplandeça a luz do evangelho da glória de Cristo, o qual é a
imagem de Deus."
2 Coríntios 4:3,4
Referências: