O NeoMatrix Tech está de casa nova!

Você deverá ser redirecionado em 6 segundos. Se não, visite:
http://www.leonelfraga.com/neomatrixtech
e atualize seus favoritos.

Aviso IMPORTANTÍSSIMO!

Aviso aos navegantes:

O NeoMatrix Tech mudou de casa!!!

A partir de agora, acessem pelo novo endereço:

http://www.leonelfraga.com/neomatrixtech

Ué... mas é só o domínio mudou de lugar?

R: Na verdade, não é bem assim hehe. Este domínio que você acessa agora aponta para um blog hospedado no Blogger, enquanto no novo, aponta para um blog na plataforma Wordpress, hospedagem própria, muito mais rápida e com um layout mais agradável de ler ;)

Não vou fechar este domínio igual ao que eu fiz com o NM Light (que já está 100% na nova plataforma). Talvez beeeeeeem depois eu faça isso.

Todos os posts daqui se encontram lá, e novos posts serão colocados somente no novo endereço.
A única coisa que não consegui importar foram os comentários. Mas em breve vai ter um post contando sobre a epopéia que foi migrar o NeoMatrix Tech!

Somente vou fechar a área de comentários daqui. Caso queiram comentar, favor ver o post correspondente no "Novo NeoMatrix Tech" e comentem por lá. É bem melhor! (pena que os permalinks "amigáveis para SEO" não funcionam lá, dá erro 404 e não consigo fazer a configuração funcionar. E olha que eu já vi vários artigos falando desse assunto :( ).

Quem assina o feed, já está lendo o conteúdo do novo NeoMatrix Tech!

sábado, 25 de abril de 2009

Armadilhas do C# – Atribuições, população de listas e referências

Uma vez precisei corrigir uma aplicação (lembra daquela que comentei no último Momento POG quando abordei o GOTO?) que necessitava enviar mensagens para o webservice, e quando mais de uma mensagem era mandada TODAS as mensagens eram enviadas apenas com a última buscada.

Vou explicar melhor:

De acordo com um assunto, era populada uma lista a partir de um banco de dados, porém no final do código todos os itens desta lista ficavam iguais ao último item que era buscado da base.

Você consegue notar a diferença entre os códigos abaixo, depois do break?

Código I:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4:  
   5: namespace ConsoleApplication1
   6: {
   7:     public class Teste
   8:     {
   9:         public string algumacoisa = "";
  10:     }   
  11:     
  12:     class Program
  13:     {
  14:         static void Main(string[] args)
  15:         {
  16:             string[] lista = new string[3] { "Primeiro", "Segundo", "Terceiro" };            
  17:             List<Teste> l = new List<Teste>();
  18:             Teste x = new Teste();
  19:             foreach (string s in lista)
  20:             {
  21:                 x.algumacoisa = s;
  22:                 l.Add(x);
  23:             }
  24:             foreach (Teste saida in l)
  25:             {
  26:                 Console.WriteLine(saida.algumacoisa);
  27:             }
  28:             Console.ReadKey();
  29:         }
  30:     }
  31: }

Código II:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4:  
   5: namespace ConsoleApplication1
   6: {
   7:     public class Teste
   8:     {
   9:         public string algumacoisa = "";
  10:     }   
  11:     
  12:     class Program
  13:     {
  14:         static void Main(string[] args)
  15:         {
  16:             string[] lista = new string[3] { "Primeiro", "Segundo", "Terceiro" };            
  17:             List<Teste> l = new List<Teste>();
  18:             foreach (string s in lista)
  19:             {
  20:                 Teste x = new Teste();
  21:                 x.algumacoisa = s;
  22:                 l.Add(x);
  23:             }
  24:             foreach (Teste saida in l)
  25:             {
  26:                 Console.WriteLine(saida.algumacoisa);
  27:             }
  28:             Console.ReadKey();
  29:         }
  30:     }
  31: }

Exceto pela variável “x” (um objeto da classe Teste) que é declarada fora do laço foreach no Código I, enquanto que no Código II ela é declarada dentro do laço, não há nenhuma outra diferença entre eles.

Mas esta sutil diferença de código modificou COMPLETAMENTE o resultado do programa. Vejam as capturas de tela com o resultado da execução dos dois programas:

Código I:

Resultado do Código I (Errado)Código II:

Resultado do Código II (Correto)Mas por que isso ocorreu?

Quando estamos trabalhando com um objeto, no nosso caso a variável “x”, e utilizamos o comando new() estaremos criando uma referência do mesmo na memória. Quando, em um List ou em qualquer outra coleção adicionamos este objeto dentro de seus itens, na verdade estaremos adicionando esta referência de memória do nosso objeto.

No Código I, ao fazer a iteração do array lista, atribuímos seus valores dentro da instância de Teste em x na propriedade “algumacoisa” e em seguida adicionamos este objeto no List<> l.

Como fazemos três iterações, adicionamos três objetos dentro do List<> não é? ERRADO.

Na verdade, adicionamos a referência à variável x três vezes, e como ela foi inicializada apenas uma vez com o comando new adicionamos a mesma referência três vezes.

Então, ao modificar o valor desta referência, estaremos modificando em todos os lugares onde ela é mencionada, no nosso caso, em cada item do List<> l.

Já no Código II, ao criar uma nova instância da classe Teste em x a cada iteração, estaremos adicionando ao nosso List<> três referências diferentes, sendo que ao final de cada iteração a referência criada existirá apenas dentro do List<>. E como x tem escopo apenas dentro do laço foreach, não poderemos mais utilizá-la, sendo que para acessar cada referência criada a partir de agora, só a partir do List<>.

Como você viu, um detalhezinho sutil e que fez uma diferença tremenda…

Um abraço! 

2 comentários:

Lucho 2 de mai. de 2009, 15:06:00  

As armadilhas da POO. :)

Leonel Fraga de Oliveira 2 de mai. de 2009, 15:42:00  

@Lucho

Pensando de uma forma mais ampla, é isso mesmo :-)


Postar um comentário

Para tornar este artigo ainda mais interessante, escreva suas críticas (desde que construtivas e sem ofenças), elogios, sugestões, complementos, dúvidas, etc, etc, etc!!!

Sobre o NeoMatrix Tech

Meu blog para assuntos profissionais, ligado com tecnologia.
Dicas de programação (grande parte de C# e ASP.NET, mas não limitado a essa plataforma :-) ), dicas de utilitários, análises de equipamentos e serviços, resenhas sobre sites que eu visito, relacionados com tecnologia, opinião sobre mercado de trabalho, metodologias de desenvolvimento, comportamento no mundo tecnológico...

NeoMatrix Light

  © Blogger templates ProBlogger Template by Ourblogtemplates.com 2008 - Editado e configurado por Leonel F.

Voltar ao TOPO