none
Passar List<T> como parâmetro para um Form - C# Windows Form RRS feed

  • Pergunta

  • Olá pessoa do fórum, estou com uma grande dúvida a cerca de passar uma lista genérica como parâmetro para um outro form do meu projeto. A principio eu passei essa List<T> como valor para o formulário porém está acontecendo algo muito estranho, ao realizar qualquer alteração nesta lista no segundo formulário a mesma é alterada no formulário principal, como se ambas tivesse com o mesmo endereço de memória, e esse comportamento ocorre apenas com as List<T>. Segue abaixo um pequeno exemplo para ficar mais claro a minha dúvida.

    Formulário Secundário

    public List<Pessoa> listaPessoaSecundaria;
    
            public Form2(List<Pessoa> listaPessoa)
            {
                InitializeComponent();
                listaPessoaSecundaria = listaPessoa;
            }
    


    Formulário Primário

            List<Pessoa> listaPessoaPrincipal;
    
            private void Form1_Load(object sender, EventArgs e)
            {
                listaPessoaPrincipal = ObterListaPessoa();
                dataGridView1.DataSource = listaPessoaPrincipal;
            }
            
            private void button1_Click(object sender, EventArgs e)
            {
                Form2 secundario = new Form2(listaPessoaPrincipal);
    
                if (secundario.ShowDialog() == DialogResult.OK)
                {
                    listaPessoaPrincipal = secundario.listaPessoaSecundaria;
                    dataGridView1.DataSource = null;
                    dataGridView1.DataSource = listaPessoaPrincipal;
                }
                else
                {
                    dataGridView1.DataSource = null;
                    dataGridView1.DataSource = listaPessoaPrincipal;
                }
            }

    Se alguém puder me ajudar serei muito grato.


    quinta-feira, 3 de março de 2016 11:31

Respostas

  • Não, veja uma explicação aqui https://msdn.microsoft.com/pt-br/library/14akc2c7.aspx?f=255&MSPPError=-2147217396 . Particularmente eu uso REF em tipos primários (int, double, float...) para serem passados como referencia. 

    int x = 1;
    Change(ref x);
    Debug.Assert(x == 5); // true
    WillNotChange(x);
    Debug.Assert(x == 5); // false - x não está com valor 10
    
    void Change(ref int x)
    {
      x = 5;
    }
    
    void WillNotChange(int x)
    {
      x = 10;
    }

    Objetos no C# são passados como referência (tirando string que é um caso a parte, http://stackoverflow.com/questions/1096449/c-sharp-string-reference-type).


    Att. Andre de Mattos Ferraz - www.iamferraz.com.br - http://mbsy.co/ldecrespigny/19022985



    quinta-feira, 3 de março de 2016 13:49
  • Tem, vc clona ela e passa :D

    veja aqui http://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c

    var newList = oldList.ToList();


    Att. Andre de Mattos Ferraz - www.iamferraz.com.br - http://mbsy.co/ldecrespigny/19022985



    quinta-feira, 3 de março de 2016 14:09
  • Anderson bom dia!

    Tem  um tópico bem explicativo no StackOverFlow que deve te ajudar:

    Passagem por valor ou por referência

    Resumindo, o que é dito é que quando você passar a referencia do objeto é como se você tivesse dois objetos iguais, apontando pro mesmo local na memória sim. Enquanto quando você passar por valor, você faz uma cópia do valor e armazena no objeto novo.

    Olha um exemplo bobo que fiz aqui:

        class Program
        {
            static void Main(string[] args)
            {
                Animal animal1 = new Animal();
                animal1.Tipo = "Mamífero";
                animal1.Nome = "Totó";
    
                Animal animal2 = new Animal();
                animal2.Tipo = "Peixe";
                animal2.Nome = "Linguado";
    
                animal1.Nome = animal2.Nome;
    
                Console.WriteLine(animal1.Nome);
                //Imprime Linguado
                Console.WriteLine(animal1 == animal2);
                //Imprime False
                Console.ReadKey();
    
                animal2.Nome = "Qualquer Coisa";
    
                Console.WriteLine(animal1.Nome);
                //Imprime Linguado, pois ele copiou este valor do objeto animal2 e mesmo com a alteração do objeto animal2, não houve alteração no objeto animal1
                Console.WriteLine(animal1 == animal2);
                //Imprime false
                Console.ReadKey();
    
                animal1 = animal2;
                animal2.Nome = "Qualquer Coisa de novo";
    
                Console.WriteLine(animal1.Nome);
                //Imprime Qualquer Coisa de novo, pois agora animal1 é apontado para o mesmo local de animal2
                Console.WriteLine(animal1 == animal2);
                //Imprime True
                Console.ReadKey();
            }
        }

    Veja se te ajuda.

    Abraços!

    quinta-feira, 3 de março de 2016 14:24

Todas as Respostas

  • Anderson List<Pessoa> é passado por referencia e não por cópia. Então qualquer alteração em um form afeta a referência principal.

    Att. Andre de Mattos Ferraz - www.iamferraz.com.br - http://mbsy.co/ldecrespigny/19022985

    quinta-feira, 3 de março de 2016 13:07
  • Obrigado pela resposta André, porém eu tenho uma dúvida para ser por referência não seria:

    public Form2(ref List<Pessoa> listaPessoa)
            {
                InitializeComponent();
                listaPessoaSecundaria = listaPessoa;
            }

    Você informou na sua resposta que List<Pessoa> está sendo passada por referência, então qual seria a forma de passar uma cópia apenas. Para que listaPessoaPrincipal e listaPessoaSecundaria sejam diferente.

    quinta-feira, 3 de março de 2016 13:30
  • Não, veja uma explicação aqui https://msdn.microsoft.com/pt-br/library/14akc2c7.aspx?f=255&MSPPError=-2147217396 . Particularmente eu uso REF em tipos primários (int, double, float...) para serem passados como referencia. 

    int x = 1;
    Change(ref x);
    Debug.Assert(x == 5); // true
    WillNotChange(x);
    Debug.Assert(x == 5); // false - x não está com valor 10
    
    void Change(ref int x)
    {
      x = 5;
    }
    
    void WillNotChange(int x)
    {
      x = 10;
    }

    Objetos no C# são passados como referência (tirando string que é um caso a parte, http://stackoverflow.com/questions/1096449/c-sharp-string-reference-type).


    Att. Andre de Mattos Ferraz - www.iamferraz.com.br - http://mbsy.co/ldecrespigny/19022985



    quinta-feira, 3 de março de 2016 13:49
  • Então não existe nenhuma forma de passar apenas uma cópia de List<Pessoa> para o segundo formulário? Sem comprometer os dados do formulário principal?
    quinta-feira, 3 de março de 2016 14:07
  • Tem, vc clona ela e passa :D

    veja aqui http://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c

    var newList = oldList.ToList();


    Att. Andre de Mattos Ferraz - www.iamferraz.com.br - http://mbsy.co/ldecrespigny/19022985



    quinta-feira, 3 de março de 2016 14:09
  • Anderson bom dia!

    Tem  um tópico bem explicativo no StackOverFlow que deve te ajudar:

    Passagem por valor ou por referência

    Resumindo, o que é dito é que quando você passar a referencia do objeto é como se você tivesse dois objetos iguais, apontando pro mesmo local na memória sim. Enquanto quando você passar por valor, você faz uma cópia do valor e armazena no objeto novo.

    Olha um exemplo bobo que fiz aqui:

        class Program
        {
            static void Main(string[] args)
            {
                Animal animal1 = new Animal();
                animal1.Tipo = "Mamífero";
                animal1.Nome = "Totó";
    
                Animal animal2 = new Animal();
                animal2.Tipo = "Peixe";
                animal2.Nome = "Linguado";
    
                animal1.Nome = animal2.Nome;
    
                Console.WriteLine(animal1.Nome);
                //Imprime Linguado
                Console.WriteLine(animal1 == animal2);
                //Imprime False
                Console.ReadKey();
    
                animal2.Nome = "Qualquer Coisa";
    
                Console.WriteLine(animal1.Nome);
                //Imprime Linguado, pois ele copiou este valor do objeto animal2 e mesmo com a alteração do objeto animal2, não houve alteração no objeto animal1
                Console.WriteLine(animal1 == animal2);
                //Imprime false
                Console.ReadKey();
    
                animal1 = animal2;
                animal2.Nome = "Qualquer Coisa de novo";
    
                Console.WriteLine(animal1.Nome);
                //Imprime Qualquer Coisa de novo, pois agora animal1 é apontado para o mesmo local de animal2
                Console.WriteLine(animal1 == animal2);
                //Imprime True
                Console.ReadKey();
            }
        }

    Veja se te ajuda.

    Abraços!

    quinta-feira, 3 de março de 2016 14:24
  • Valeu pela indicação do tópico Rogério, porém a resposta que o André de Mattos deu funcionou perfeitamente... Mesmo assim muito obrigado... E obrigado André, funcionou direitinho e mais do que isso serviu de aprendizagem também.
    quinta-feira, 3 de março de 2016 14:32