Quando é copiado um valor / object C # e quando é copiado sua referência?

Eu continuo recebendo o mesmo problema repetidamente onde um object que eu quero referenciar é copiado ou onde um object que eu quero copiar é referenciado. Isso acontece quando eu uso o operador =.

Por exemplo, se eu estou enviando o object para outro formulário, ou seja:

SomeForm myForm = new SomeForm(); SomeObject myObject = new SomeObject(); myForm.formObject = myObject; 

… e depois modificar o object no formulário, o object original não é modificado. É como se o object fosse copiado e não referenciado. No entanto, quando faço isso:

 SomeObject myObject = new SomeObject(); SomeObject anotherObject = new SomeObject(); anotherObject = myObject; 

… e, em seguida, modifique anotherObject , myObject será modificado.

O caso mais agravante é quando tento clonar um dos meus objects definidos:

 public class SomeObject { double value1, value2; //default constructor here public SomeObject(val1, val2) { value1 = val1; value2 = val2; } public void Clone(SomeObject thingToCopy) { this.value1 = thingToCopy.value1; this.value2 = thingToCopy.value2; } } 

quando eu faço isso …

 SomeObject obj1 = new SomeObject(1, 2); SomeObject obj2 = new SomeObject(); obj2.Clone(obj1); 

obj1 é referenciado e quaisquer modificações no obj1 alteram obj1 .

Objetos do sistema como int, double, string , etc parecem sempre ser copiados, exceto no caso do método clone acima.

Minha pergunta é, não levar em conta o uso da palavra-chave ref em funções, quando um object é copiado e quando um object é referenciado em cada caso (isto é, ao passar para funções, ao configurar como outros objects (como os dois primeiros exemplos acima), ao copiar variables ​​de membro como o terceiro exemplo, etc.)?

É difícil responder a esse tipo de pergunta com precisão, sem gastar muito tempo escolhendo suas palavras cuidadosamente.

Eu fiz isso em alguns artigos que você pode achar útil:

  • Parâmetro que passa em C # / .NET
  • Tipos de referência e tipos de valor em C # / .NET

Isso não quer dizer que os artigos são perfeitos, é claro – longe disso – mas eu tentei ser o mais claro que pude.

Eu acho que uma coisa importante é separar os dois conceitos (passagem de parâmetros e tipos de valor de referência vs) em sua cabeça.

Para ver seus exemplos específicos:

 SomeForm myForm = new SomeForm(); SomeObject myObject = new SomeObject(); myForm.formObject = myObject; 

Isso significa que myForm.formObject e myObject referem-se à mesma instância de SomeObject – como duas pessoas que possuem pedaços de papel separados, com cada um tendo o mesmo endereço escrito neles. Se você for ao endereço em um pedaço de papel e pintar a casa em vermelho, então vá para o endereço no segundo pedaço de papel, você verá uma casa vermelha.

Não está claro o que você quer dizer com “e depois modificar o object no formulário” porque o tipo que você forneceu é imutável. Não há como modificar o object em si. Você pode alterar myForm.formObject para se referir a uma instância diferente de SomeObject , mas isso é como rabiscar o endereço em um pedaço de papel e escrever um endereço diferente nele. Isso não vai mudar o que está escrito no outro pedaço de papel.

Se você pudesse fornecer um programa curto, mas completo , cujo comportamento você não entende (idealmente um aplicativo de console, apenas para manter as coisas mais curtas e simples), seria mais fácil falar sobre as coisas em termos concretos.

Oi Mike Todos os objects, que deriva de ValueType, como struct ou outros tipos primitivos, são tipos de valor. Isso significa que eles são copiados sempre que você os atribui a uma variável ou os transmite como um parâmetro de método. Outros tipos são tipos de referência, isso significa que, quando você atribui um tipo de referência a uma variável, não é seu valor, mas seu endereço no espaço de memory é atribuído à variável. Além disso, você deve observar que pode passar um tipo de valor como referência usando a palavra-chave ref. Aqui está a syntax

 public void MyMethod(ref int a) { a = 25 } int i = 20; MyMethod(ref i); //Now i get's updated to 25. 

Espero que ajude 🙂

Com relação à clonagem de seus objects, se os valores que você está copiando de um object para outro forem tipos de referência, qualquer modificação nesses valores no object original afetará os valores no object copiado (já que eles são apenas referências ao mesmo object)

Se você precisar clonar um object que tenha propriedades que sejam tipos de referência, será necessário torná-las clonáveis ​​ou fazer uma cópia manual delas, instanciando novas instâncias conforme necessário.

Considere usar a interface IClonable , embora não seja a melhor das soluções.