¿El tipo de referencia todavía necesita pasar por ref?

Considere el siguiente código (por simplicidad, no seguí ninguna regla de encoding de C #).

public class Professor { public string _Name; public Professor(){} public Professor(string name) { _Name=name; } public void Display() { Console.WriteLine("Name={0}",_Name); } } public class Example { static int Main(string[] args) { Professor david = new Professor("David"); Console.WriteLine("\nBefore calling the method ProfessorDetails().. "); david.Display(); ProfessorDetails(david); Console.WriteLine("\nAfter calling the method ProfessorDetails().."); david. Display(); } static void ProfessorDetails(Professor p) { //change in the name here is reflected p._Name="Flower"; //Why Caller unable to see this assignment p=new Professor("Jon"); } } 

Como se esperaba, el resultado es:

Antes de llamar al método ProfessorDetails () …

Nombre = David

Después de llamar al método ProfessorDetails () …

Nombre = Flor

La llamada p=new Professor("Jon"); en ProfessorDetails(Professor p) no es efectivo, aunque es un tipo de referencia. ¿Por qué debería todavía necesitar usar la palabra clave ref para obtener el resultado deseado?

Todo se pasa por valor en C #. Sin embargo, cuando pasa un tipo de referencia, la referencia se pasa por valor , es decir, se pasa una copia de la referencia original. Por lo tanto, puede cambiar el estado del objeto al que apunta la copia de referencia, pero si asigna un nuevo valor a la referencia, solo está cambiando a qué apunta la copia, no a la referencia original.

Cuando utiliza la palabra clave ‘ref’ le dice al comstackdor que pase la referencia original, no una copia, por lo que puede modificar a qué apunta la referencia dentro de la función. Sin embargo, la necesidad de esto suele ser rara y se utiliza con más frecuencia cuando necesita devolver múltiples valores de un método.

Un ejemplo:

 class Foo { int ID { get; set; } public Foo( int id ) { ID = id; } } void Main( ) { Foo f = new Foo( 1 ); Console.WriteLine( f.ID ); // prints "1" ChangeId( f ); Console.WriteLine( f.ID ); // prints "5" ChangeRef( f ); Console.WriteLine( f.ID ); // still prints "5", only changed what the copy was pointing to } static void ChangeId( Foo f ) { f.ID = 5; } static void ChangeRef( Foo f ) { f = new Foo( 10 ); } 

Tienes pasado por referencia y tipo de referencia mezclado.

Al cambiar p, no estás cambiando lo que apunte a p, sino a dónde está apuntando p, por así decirlo. Y como p no se ha declarado como ref, la referencia (al tipo de referencia) se pasa por valor y el cambio a p no se refleja en el código que llama a ProfessorDetails. Los cambios en la instancia p señalaba se reflejan (ya que es un tipo de referencia). El profesor hubiera sido un tipo de valor, ni siquiera esos cambios serían visibles en el código de llamada.

Hay una diferencia entre pasar una referencia y una referencia a una referencia.

Cuando pasa un objeto (de un tipo de referencia), el destinatario puede modificar los datos del objeto a través del puntero subyacente, pero si el destinatario modifica la referencia, cuando la función retorna, el llamante no lee la referencia modificada fuera de la stack. El destinatario no puede cambiar a qué objeto se hace referencia.

Cuando pasa un objeto por referencia, el destinatario recibe una referencia a la referencia. El destinatario tiene un puntero a la referencia original, por lo que puede modificar la referencia (cambiando así el objeto al que apunta la referencia) además de modificar el objeto al que apunta la referencia.

El valor real de p es una referencia a la misma instancia de profesor que David. Las llamadas que realice en esa referencia se desreferencian como llamadas a la misma instancia que las llamadas realizadas en david be. Sin embargo, p es una copia de esa referencia, no es lo mismo que el valor de David.

Por lo tanto, cuando p = nuevo Profesor (), está cambiando el valor de la variable de referencia para apuntar a una nueva instancia. Sin embargo, eso no modifica la referencia de David, que aún apunta a la instancia anterior.

Si pasara p como ref, el valor de p sería una referencia a la variable de referencia de david. Modificarlo realmente modificaría el valor de david para apuntar a una nueva instancia.

En cuanto a ‘pasar un tipo de referencia’ frente a ‘pasar por ref (usando la palabra clave ref)’, después de mi investigación mi conclusión es esta:

Si tiene un objeto tipo de referencia y mantiene este objeto pasando de un método a otro, todo el tiempo que los objetos apuntan a una determinada ubicación de la memoria. Si trabaja en este objeto, por ejemplo, cambiando el valor de la propiedad, esto provocará un cambio en el objeto original. Piensa como si en los diferentes métodos estuvieras hablando de la misma persona todo el tiempo; y en un método, cambiaste el color de la camisa de esa persona. Entonces eso causará un cambio en el objeto de la persona original también.

Pero, en su camino de saltar de un método a otro, si crea una nueva referencia para el objeto (como lo está haciendo escribiendo ‘p = nuevo Profesor (‘ Jon ‘)’), básicamente está rompiendo el vínculo entre el objeto en un nuevo método y el objeto original. Tu ‘p’ ahora hace referencia a otra ubicación en la memoria. Entonces, cualquiera que sea el cambio que realice en esta nueva ubicación de la memoria, no tendrá ningún efecto en absoluto sobre el objeto original. Sin embargo, si desea cambiar la dirección del objeto original y tener el enlace, debe usar la palabra clave ref. BECA PARA UTILIZAR LA PALABRA CLAVE REF, porque una vez en cualquier método, la dirección original en la memoria cambia a una nueva dirección (usando la palabra clave ref), todos los cambios en el objeto original hecho en otros métodos ahora se han ido.

Cada tipo de referencia pasa por valor a una llamada a método. Entonces puede modificar los datos dentro de su instancia porque apunta al mismo lugar, pero si desea modificar la instancia, debe usar ref

 public class Professor { public string _Name; public Professor(){} public Professor(string name) { _Name=name; } public void Display() { Console.WriteLine("Name={0}",_Name); } } public class Example { static int Main(string[] args) { Professor david = new Professor("David"); Console.WriteLine("\nBefore calling the method ProfessorDetails().. "); david.Display(); ProfessorDetails(ref david); Console.WriteLine("\nAfter calling the method ProfessorDetails().."); david. Display(); } static void ProfessorDetails(ref Professor p) { //change in the name here is reflected p._Name="Flower"; //Why Caller unable to see this assignment p=new Professor("Jon"); } }