Duvida C Sharp (Passagem Objeto sem Referencia)
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.
Impressão Console:
X = 10 Y = 10 Z = 10
X = 25330 Y = 23710 Z = -83190
X = 25330 Y = 23710 Z = -83190
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
Curtidas 1
Melhor post
Rodrigo Duclerc
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:
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:
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):
Então finalmente:
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:
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!
É 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!
GOSTEI 2
Mais Respostas
Renan Daros
09/02/2018
Rodrigo, muito obrigado pela explicação, farei uso da sua ideia para obter os resultados desejados no meu código. Muito Obrigado por tudo.
GOSTEI 0