Fórum Duvida C Sharp (Passagem Objeto sem Referencia) #591278

09/02/2018

0

C#

Pessoal,

estou aprendendo c# e desenvolvendo um projeto para o meu curso de cartografia, estou com um problema de passagem de um objeto para um método, no qual preciso realizar alguns cálculos sem modificar o objeto original, utilizado na passagem. Infelizmente não consigo isolar o mesmo toda vez, pois é um método iterativo. Devido meu código ser extenso, irei colocar um código simplificado para que entendam o meu caso. Desde já agradeço pela atenção de todos.

 class Coord
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }

        public Coord(double x, double y, double z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }

        public void imprimir()
        {
            Console.WriteLine("X = " + this.X + " Y = " + this.Y + " Z = " + this.Z);
        }
    }



class Funcoes
    {
        //Diversas Funcoes
        public Coord Calculo(Coord XYZ)
        {
            for (Int16 i = 0; i < 10; i++)
            {
                XYZ.X = XYZ.X - XYZ.Y - XYZ.Z;
                XYZ.Y = XYZ.Y - XYZ.X - XYZ.Z;
                XYZ.Z = XYZ.Z - XYZ.Y - XYZ.X;
            }

            return XYZ;
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            Coord coord1 = new Coord(10, 10, 10);
            coord1.imprimir();
            Funcoes func = new Funcoes();

            Coord coord2 = func.Calculo(coord1);

            coord1.imprimir();
            coord2.imprimir();

            Console.Read();
        }
    }


Impressão Console:

X = 10 Y = 10 Z = 10
X = 25330 Y = 23710 Z = -83190
X = 25330 Y = 23710 Z = -83190
Renan Daros

Renan Daros

Responder

Post mais votado

09/02/2018

Olá Renan, tudo bom?

É comum ficarmos confusos em casos como o que vc apresenta em seu exemplo.

No C# existem dois tipos principais: Tipos de Referência e de Valor. Classes, delegates e interfaces são tipos de referência. int, float, enum, decimal (e por ai vai) são tipos de valor. Eles funcionam de forma diferente. Referência é um tipo que não guarda o valor propriamente dito, mas uma referência àquele valor em um espaço na memória. Ao passo que o tipo Valor realmente guarda aquele valor em uma área da memória.

Veja estas linhas, por exemplo:
            int x = 10; 
            Coord coord1 = new Coord(10, 10, 10);


Quando dizemos que X = 10, o que ocorre por baixo dos panos? Uma área da memória é alocada para armazenar o valor 10. Int é um tipo de valor (Value Type).

Mas e Quando damos um Coord coord1 = New Coord(10, 10, 10) ? Diferentemente do que ocorre com int, o objeto coord1 não guarda os valores de seus atributos. O que coord1 guarda é um endereço (uma referência) para o espaço da memória onde estão guardados os valores.

Apenas para exemplificar, digamos que este endereço da memória que coord1 guarda é 02A. É neste lugar da memória (um lugar chamado 02A) que estão armazenados os valores dos atributos etc.

Matenha isso em mente.

Veja agora o momento onde você invoca o método:
Coord coord2 = func.Calculo(coord1);


Quando você faz func.Calculo(coord1); o que você está passando para o método?
Você está passando um objeto guarda uma referência ao endereço 02A. (lembra ali em cima?)

Agora observe a implementação do seu método Calculo (fiz comentários em algumas linhas para ficar mais claro):

public Coord Calculo(Coord XYZ)//está recebendo um objeto que referencia um espaço na memória cujo endereço é 02A
        {
            for (Int16 i = 0; i < 10; i++)
            {
                //Os cálculos são feitos nos atributos existentes no espaço na memória cujo endereço é 02A
                XYZ.X = XYZ.X - XYZ.Y - XYZ.Z;
                XYZ.Y = XYZ.Y - XYZ.X - XYZ.Z;
                XYZ.Z = XYZ.Z - XYZ.Y - XYZ.X;
            }
 
            return XYZ; //Por fim, está devolvendo o mesmo objeto que guarda uma referência ao endereço 02A
        }


Então finalmente:
coord1.imprimir(); //Invoca o método imprimir do objeto que referencia o endereço 02A
coord2.imprimir(); //invoca o método imprimir do mesmo objeto que referencia pelo endereço 02A


Portanto, apesar de serem duas variáveis. Tanto uma quanto a outra apontam para a mesma referência. Assim, modificando o valor de uma, o valor da outra é alterado também.

Experimente modificar seu método para que ele fique assim:

 public Coord Calculo(Coord XYZ)
        {
            Coord resultado = new Coord();
            resultado.X = XYZ.X;
            resultado.Y = XYZ.Y;
            resultado.Z = XYZ.Z;

            for (Int16 i = 0; i < 10; i++)
            {
                resultado.X = resultado.X - resultado.Y - resultado.Z;
                resultado.Y = resultado.Y - resultado.X - resultado.Z;
                resultado.Z = resultado.Z - resultado.Y - resultado.X;
            }
 
            return resultado;
        }


Fazendo um Coord resultado = new Coord(); estamos criando um novo objeto que guarda uma outra referência. Dessa forma, não afetamos o objeto original.

A solução é simples, mas o conceito por trás disso é realmente complicado de entender. Sinta-se a vontade para entrar em contato novamente e tirar suas dúvidas.

Um abraço e até mais!

Rodrigo Duclerc

Rodrigo Duclerc
Responder

Gostei + 2

Mais Posts

10/02/2018

Renan Daros

Rodrigo, muito obrigado pela explicação, farei uso da sua ideia para obter os resultados desejados no meu código. Muito Obrigado por tudo.
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar