Economizando bits
C# - LINQ SelectMany
Bom, a pedido do Cristiano Carvalho, neste post e nos próximos estarei comentando sobre os métodos LINQ que considero mais importante.
Se tiverem alguma sugestão ou pedido de outros métodos, por favor.
First(), FirstOrDefault(), Single(), Last(), LastOrDefault()
OrderBy(), OrderByDescending()
Skip(), SkipWhile()
Take(), TakeWhile()
LINQ SelectMany()
Neste post falarei sobre um método que conheci a pouco tempo e achei interessante, pois nos permite economizar algumas linhas de código, deixando o mesmo mais legível. Este método é o SelectMany.
Temos uma rede de colégios onde cada colégio tem seus professores com suas devidas matérias(matemárica, física, portugues...)
Queremos então selecionar todos os professores que lecionam Matemática.
Para resolvermos esse problema necessitaríamos de 1 loop dentro de outro loop:
Seleção dos professores utilizando ForEach dentro de ForEach
Não é um código muito grande, muito menos complexo, porém poderíamos obter o mesmo resultado da seguinte forma:
Seleção dos professores utilizando SelectMany
O SelectMany tem uma sintaxe muito simples, vamos explicar:
No exemplo acima, damos o nome de cada um dos colégios de colegio. Com 'FiltrarProfessoresQueConhecemMateria(colegio.Professores, materia)', dissemos que queremos selecionar cada um dos professores que conhecem a matéria passada por parâmetro, então todos os professores são unidos em uma única lista.
Se quiséssemos selecionar apenas o nome dos professores que conhecem tal matéria, como ficaria então?
Seleção do nome dos professores utilizando SelectMany
Para selecionar uma propriedade do item selecionado (no caso o professor), colocamos uma segunda expressão contendo:
professores representa a lista dos professores que está sendo criada item a item e professor é cada um dos professores. Basta dizer que queremos selecionar professor.Propriedade
Criamos um exemplo que imprime o id de cada um dos professores encontrados em cada um dos métodos, utilizando o ForEach e utilizando o SelectMany, para mostrar que ambos tiveram o mesmo resultado.
Ids dos professores
Abaixo disponibilizarei as classes utilizadas. O código-fonte pode ser obtido através do link(source) ou no git:
http://github.com/fsaalmeidinha/linq_selectmany.git
Colegio.cs
Materia.cs
ColegioFactory.cs
TestLinqSelectMany.cs
Postado por Felipe Almeida às 20:16 Links para esta postagem
Vaga para programador Delphi 2007, ASP.NET/C#
Vaga para programador Delphi 2007, ASP.NET/C#; Conhecimento em banco de dados SQL Server 2008 R2; HTML, CSS3, JavaScript
É um diferencial se o candidato possuir conhecimentos com (WebForms, WebService, JSON) e E-Commerce com integração com gateway de pagamento
Programação voltada para sistemas web e desktop.
HTML e CSS3;
Demais detalhes, envie email para Taína Medeiros com o CV atualizado e pode mandar a url da vaga aqui do blog para ela se localizar.
Postado por Felipe Almeida às 09:24 Links para esta postagem
C# - LINQ First(), FirstOrDefault(), Single(), Last(), LastOrDefault()
LINQ First(), FirstOrDefault(), Single(), Last(), LastOrDefault()
Neste post falarei sobre os métodos First, FirstOrDefault, Single, Last e LastOrDefault do LINQ, que são muito simples, mas exigem cuidado.
Todos são métodos de busca com uma sobrecarga que permite que seja atribuído um predicado à busca, ou seja, podemos fazer uma busca em uma lista de números inteiros, onde o predicado é: "que seja maior do que 10", por exemplo.
int primeiroNumeroMaiorQueDez = listaDeNumerosInteiros.First(numero => numero > 10);
Apesar dos métodos First e FirstOrDefault fazerem praticamente a mesma coisa, eles tem algumas diferenças, que serão discutidas adiante:
Fizemos um teste, buscando em uma lista de números inteiros, o primeiro elemento com o valor 100, através do método FIRST, sendo que na lista existia tal número.
Teste FIRST em uma lista com o elemento procurado
Em seguida fizemos o mesmo teste, em uma lista que não contém o número 100, o que nos levaria a uma dúvida: "O que o método irá nos retornar então?". A resposta é: "Uma exception".
Teste FIRST em uma lista sem o elemento procurado
Porém, em alguns momentos, gostaríamos de recuperar o elemento procurado apenas se ele existir, e se não existir, queremos que um valor default seja retornado, sem gerar exception, que no caso de uma lista de números inteiros é o número 0.
Neste caso, devemos utilizar o método FIRSTORDEFAULT:
Teste FIRSTORDEFAULT em uma lista sem o elemento procurado
Outro método que busca um elemento em uma lista é o Single, com o diferencial de que tal método, está esperando procurar um elemento único em uma lista, portanto o número de ocorrências do número procurado na lista não pode ser diferente de 1:
Teste SINGLE em uma lista sem o elemento procurado
Teste SINGLE em uma lista com apenas uma ocorrência do número procurado
Teste SINGLE em uma lista com mais de uma ocorrência do número procurado
Os métodos Last e LastOrDefault, se assemelham ao Fist e FirstOrDefault respectivamente, sendo que ao invés de buscarem o primeiro elemento, buscam o ultimo.
Não confunda. Com o método FirstOrDefault, o método First e Single parecem ser inúteis, porém cada um deles tem suas utilidades, por exemplo:
Se quisermos procurar em um cadastro, onde o CPF deve ser único, um usuário que tenha o CPF = 118.187.881-00, qual método usaríamos e porque?
A resposta é: "Single", pois se existir mais de um usuário com o CPF procurado, por alguma falha na lógica do sistema, isso pode gerar um problemão.
Suponha que a intenção de buscar o usuário pelo CPF seja de debitar um valor X de sua conta, gostaria que houvesse uma confusão entre 2 usuários, ou preferiria que uma exception fosse gerada para que sua equipe pudesse analisar o problema?
https://github.com/fsaalmeidinha/LinqFirst_Single_Last.git
TestLinqMethods.cs
Postado por Felipe Almeida às 19:17 Links para esta postagem
C# - LINQ Select
LINQ Select()
Neste post falarei sobre o método Select do LINQ.
Como o próprio nome já diz, a função do método select é selecionar algo
Temos uma lista de usuários e queremos selecionar apenas os Ids desses usuários para trabalhar com uma estrutura mais simples e leve
Selecionar os ids dos usuários
Podemos também selecionar objetos anônimos
Temos de listar os usuários, mas aos invés de retornar os campos do objeto Usuario, queremos retornar outros campos. O detalhe é que o retorno desse select deve ser armazenado em uma variável do tipo object ou VAR (variáveis não tipadas):
Queremos retornar um novo objeto com:
Id: Igual ao do usuário
Descricao: NomeUsuario(EmailUsuario) - 'Ex: Felipe Almeida(felipe.silvalmeida@gmail.com)'
Select anônimo
Outra curiosidade que poucos conhecem, é a possibilidade de incluir o índice do objeto na lista, no método select, ou seja, agora temos algo do tipo:
usuarios.Select((usuario,indice) => new { IndiceNaLista = indice, NomeUsuario = usuario.Nome });
Select com índice
http://github.com/fsaalmeidinha/linq_select.git
LinqSelect.cs
Usuario.cs
Postado por Felipe Almeida às 22:39 Links para esta postagem
Neste post, acredito que vou ajudar muitas pessoas que trabalham com enumeradores em seus códigos. Vou falar sobre Extension Methods.
Para quem já utilizou os métodos que o System.Linq disponibiliza, de uma forma ou de outra já utilizou métodos de extensão.
Já repararam que quando incluimos o pacote System.Linq em nosso código, as nossas listas passam a ter novos métodos como 'First', 'FirstOrDefault', 'Select', entre outros?
Ótimo, esses são métodos de extensão da interface IEnumerable, ou seja, todas as formas de listagem a partir de agora possuem tais métodos.
Para quem já conhecia o System.Linq, nunca se perguntou como esses métodos apareceram nos nossos objetos IEnumerable? Eu me perguntava há um tempo atrás, antes de conhecer os métodos de extensão, mas pensava que não seria possível criar os meus próprios métodos de extensão, e ai que me enganei.
Há alguns meses, por acaso acabei descobrindo como esses métodos aparecem em nossos objetos, e acredite, é de uma forma muito simples.
Por exemplo, quero criar um método de extensão para os objetos do tipo String, para verificar o tamanho de uma string(assim como o método Length faz), mas com um diferencial de quando a string for nula, quero que seja retornado length = 0 ao invés de obter uma NULL POINTER EXCEPTION.
Simplesmente criaremos uma classe estática com o nome StringExtensions:
Agora basta incluir o namespace em que o StringExtensions.cs foi criado na classe em que queremos tal funcionalidade:
using ExtensionsMethods.Extensions;
A partir de então, todos os objetos do tipo string terão o método LengthOrDefault.
Legal, agora que já aprendemos como criar um método de extensão, irei mostrar como isso pode nos ajudar trabalhando com enumeradores. Digamos que temos um cadastro de usuário em um sistema e um dos campos que devem ser preenchidos é o tipo de pessoa('Pessoa Física' ou 'Pessoa Jurídica').
Como sabemos, um enumerador não tem descrição, mas ao mesmo tempo, não gostaríamos que na nossa tela, as opções apresentadas fossem 'PessoaFisica', 'PessoaJuridica', ignorando acentuação e o espaço entre as palavras, então como faríamos para vincular uma descrição aos enumeradores? Melhor ainda, não seria perfeito se pudéssemos obter a descrição de um enumerador como uma propriedade do próprio enumerador? (ex: ETipoPessoa.Fisica.Descricao)
Faremos isso, mas ao invés de uma propriedade, iremos criar um método de extensão que recupera a descrição do enumerador através de um atributo do mesmo.
ETipoPessoa.cs
Como disse, basta incluir o namespace ExtensionMethods.Extensions na classe onde desejamos obter a descrição do enumerador e..
Executando o código obtivemos o seguinte resultado:
Muito bom, agora conseguimos obter a descrição de um enumerador de forma fácil.
Basta utilizar a criatividade para criar métodos de extensão que nos ajude no nosso dia a dia.
O código fonte pode ser encontrado no link(source) ou através do git em:
https://github.com/fsaalmeidinha/extensionmethods.git
Qualquer dúvida ou crítica, podem comentar no post ou entrar em contato por email ou skype(informados à direita).
Postado por Felipe Almeida às 18:29
C# - Yield Return
Yield return é um comando que pouca gente conhece e menos ainda o utiliza, porém em alguns casos, nos ajuda e muito.
Yield return utiliza lazy-load, ou seja, carregar aos poucos.
A sintaxe do yield é muito simples:
RecuperarSerieFibonacci
Neste exemplo, temos um método que retorna a série de fibonacci (1,1,2,3,5,8...). Se prestarmos atenção no código, podemos perceber que ele não tem uma condição de parada, o que nos levaria a pensar que a execução do mesmo nunca sairia do loop, porém ai que entra o "carregar aos poucos".
Quando chamamos o método RecuperarSerieFibonacci, o valor da série só será carregado quando pedirmos, por exemplo: RecuperarSerieFibonacci().Take(10).ToList() iria processar os 10 primeiros números da série de fibonacci.
Bom, mas poderiamos fazer o mesmo sem utilizar a série de fibonacci, certo? Então qual a vantagem?
Criei um outro exemplo onde precisamos descobrir o índice de uma palavra dentro de um arquivo de texto, então, para simular o problema, criei um arquivo com cerca de 30 mil linhas e coloquei 3 palavras que deveriam ser encontradas:
1. inconstitucionalissimamente (no inicío do arquivo, proximo da linha de número 10)
2. paralelepipedo (na metade do arquivo, proximo da linha de número 15 mil)
3. pneumonia (no final do arquivo, proximo da linha de número 30 mil)
Criei também 2 métodos para retornar cada uma das palavras de cada linha do arquivo, um utilizando yield return e o outro não.
Por fim, chamei os métodos procurando cada uma das palavras, obtendo o seguinte resultado:
Como pudemos observar, em todos os casos, obtivemos um melhor resultado quando utilizamos o yield return, isso ocorreu pelos seguintes motivos:
1. Quando procuramos as palavras que estavam no inicio ou no meio do arquivo, quando não utilizamos o yield return, todo o arquivo era lido e separado por palavras para depois a palavra ser procurada, já quando utilizamos o yield return, o arquivo era lido a cada linha, fazendo com que o arquivo não precisasse ser lido por completo, economizando tempo de leitura.
2. No caso da terceira palavra, como a mesma estava no final do arquivo, então porque ainda assim a performance foi melhor? Isso ocorre pois utilizando o yield return, os valores retornados pela função não foram armazenados em memória da forma como construímos a busca.
Abaixo estou disponibilizando as classes utilizadas. O arquivo de texto utilizado para a busca só pode ser encontrado através do download do código fonte no link (source) ou fazendo download através do git em: