Armadilhas do C# – Atribuições, população de listas e referências
Leonel Fraga de Oliveira 25/04/2009 12:20

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?

Código I:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    public class Teste
    {
        public string algumacoisa = "";
    }

    class Program
    {
        static void Main(string[] args)
        {
            string[] lista = new string[3] { "Primeiro", "Segundo", "Terceiro" };
            List l = new List();
            Teste x = new Teste();
            foreach (string s in lista)
            {
                x.algumacoisa = s;
                l.Add(x);
            }
            foreach (Teste saida in l)
            {
                Console.WriteLine(saida.algumacoisa);
            }
            Console.ReadKey();
        }
    }
}

Código II:

 using System;
 using System.Collections.Generic;
 using System.Text;

 namespace ConsoleApplication1
 {
     public class Teste
     {
         public string algumacoisa = "";
     }

     class Program
     {
         static void Main(string[] args)
         {
             string[] lista = new string[3] { "Primeiro", "Segundo", "Terceiro" };
             List l = new List();
             foreach (string s in lista)
             {
                 Teste x = new Teste();
                 x.algumacoisa = s;
                 l.Add(x);
             }
             foreach (Teste saida in l)
             {
                 Console.WriteLine(saida.algumacoisa);
             }
             Console.ReadKey();
         }
     }
 }

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!

Leonel Fraga de Oliveira Leonel Fraga de Oliveira é formado em Processamento de Dados na Faculdade de Tecnologia de São Paulo (FATEC-SP - 2002) e anteriormente em Técnico em Eletrônica, pela ETE Professor Aprígio Gonzaga (lá em 1999).
Atualmente trabalha como Analista de Sistemas na Prefeitura Municipal de São Caetano do Sul - SP
Tem como hobbies DJing (também trabalha como DJ freelancer) e ciclismo, além da manutenção dos sites NeoMatrix Light e NeoMatrix Tech.
Gosta de música eletrônica, tecnologia, cinema (super fã de Jornada nas Estrelas), gastronomia e outras coisas mais.


Compartilhe nas redes sociais

   

Deixe seu comentário

comments powered by Disqus