tipo referencia por pasar pasaje parametros parametro objetos net metodos funciones como clase argumentos c# .net pass-by-reference ref

c# - referencia - ¿Por qué usar la palabra clave ''ref'' al pasar un objeto?



pasar tipo como parametro c# (11)

Si estoy pasando un objeto a un método, ¿por qué debo usar la palabra clave ref? ¿No es este el comportamiento predeterminado de todos modos?

Por ejemplo:

class Program { static void Main(string[] args) { TestRef t = new TestRef(); t.Something = "Foo"; DoSomething(t); Console.WriteLine(t.Something); } static public void DoSomething(TestRef t) { t.Something = "Bar"; } } public class TestRef { public string Something { get; set; } }

La salida es "Barra", lo que significa que el objeto se pasó como referencia.


Al utilizar la palabra clave ref con tipos de referencia, está pasando una referencia a la referencia. En muchos sentidos, es lo mismo que usar la palabra clave out pero con la pequeña diferencia de que no hay garantía de que el método realmente asigne algo al parámetro ref ''ed.


Como TestRef es una clase (que son objetos de referencia), puede cambiar el contenido dentro de t sin pasarlo como ref. Sin embargo, si pasa t como referencia, TestRef puede cambiar a lo que se refiere la t original. es decir, hacer que apunte a un objeto diferente.


Con ref puedes escribir:

static public void DoSomething(ref TestRef t) { t = new TestRef(); }

Y se cambiará después de que el método se haya completado.


Debe distinguir entre "pasar una referencia por valor" y "pasar un parámetro / argumento por referencia".

He escrito un artículo razonablemente largo sobre el tema para evitar tener que escribir con cuidado cada vez que aparece en los grupos de noticias :)


En .NET, cuando pasa cualquier parámetro a un método, se crea una copia. En tipos de valor significa que cualquier modificación que realice en el valor se encuentra en el alcance del método y se pierde al salir del método.

Al pasar un tipo de referencia, también se realiza una copia, pero es una copia de una referencia, es decir, ahora tiene DOS referencias en la memoria para el mismo objeto. Por lo tanto, si utiliza la referencia para modificar el objeto, se modifica. Pero si modifica la referencia en sí, debemos recordar que es una copia, entonces cualquier cambio también se perderá al salir del método.

Como la gente ha dicho antes, una asignación es una modificación de la referencia, por lo tanto se pierde:

public void Method1(object obj) { obj = new Object(); } public void Method2(object obj) { obj = _privateObject; }

Los métodos anteriores no modifican el objeto original.

Una pequeña modificación de tu ejemplo.

using System; class Program { static void Main(string[] args) { TestRef t = new TestRef(); t.Something = "Foo"; DoSomething(t); Console.WriteLine(t.Something); } static public void DoSomething(TestRef t) { t = new TestRef(); t.Something = "Bar"; } } public class TestRef { private string s; public string Something { get {return s;} set { s = value; } } }


Esto es como pasar un puntero a un puntero en C. En .NET, esto le permitirá cambiar a lo que se refiere la T original, personalmente , aunque creo que si está haciendo eso en .NET, probablemente tenga un problema de diseño.


Pasa una ref si quieres cambiar lo que es el objeto:

TestRef t = new TestRef(); t.Something = "Foo"; DoSomething(ref t); void DoSomething(ref TestRef t) { t = new TestRef(); t.Something = "Not just a changed t, but a completely different TestRef object"; }

Después de llamar a DoSomething, t no hace referencia al new TestRef original, sino a un objeto completamente diferente.

Esto también puede ser útil si desea cambiar el valor de un objeto inmutable, por ejemplo, una string . No puede cambiar el valor de una string una vez que se ha creado. Pero al usar una ref , puede crear una función que cambie la cadena por otra que tenga un valor diferente.

Edit: como otras personas han mencionado. No es una buena idea usar ref menos que sea necesario. El uso de ref le da libertad al método para cambiar el argumento por otra cosa, las personas que llaman al método deberán codificarse para garantizar que manejen esta posibilidad.

Además, cuando el tipo de parámetro es un objeto, las variables de objeto siempre actúan como referencias al objeto. Esto significa que cuando se utiliza la palabra clave ref tiene una referencia a una referencia. Esto le permite hacer las cosas como se describe en el ejemplo anterior. Pero, cuando el tipo de parámetro es un valor primitivo (por ejemplo, int ), si este parámetro se asigna dentro del método, el valor del argumento que se pasó se cambiará después de que el método devuelva:

int x = 1; Change(ref x); Debug.Assert(x == 5); WillNotChange(x); Debug.Assert(x == 5); // Note: x doesn''t become 10 void Change(ref int x) { x = 5; } void WillNotChange(int x) { x = 10; }


Piense en las variables (por ejemplo, foo ) de los tipos de referencia (por ejemplo, List<T> ) como que contienen identificadores de objetos de la forma "Objeto # 24601". Supongamos que la declaración foo = new List<int> {1,5,7,9}; hace que foo mantenga "Object # 24601" (una lista con cuatro elementos). Luego, al llamar a foo.Length le pedirá al objeto # 24601 su longitud, y responderá 4, por lo que foo.Length será igual a 4.

Si foo se pasa a un método sin usar ref , ese método podría hacer cambios al Objeto # 24601. Como consecuencia de tales cambios, foo.Length puede que ya no sea igual a 4. Sin embargo, el método en sí mismo no podrá cambiar foo , que continuará manteniendo "Objeto # 24601".

Pasar foo como un parámetro de ref permitirá que el método llamado realice cambios no solo al Objeto # 24601, sino también a foo . El método podría crear un nuevo Objeto # 8675309 y almacenar una referencia a eso en foo . Si lo hace, foo ya no mantendrá "Objeto # 24601", sino "Objeto # 8675309".

En la práctica, las variables de tipo de referencia no contienen cadenas de la forma "Objeto # 8675309"; ni siquiera tienen nada que pueda convertirse de manera significativa en un número. Aunque cada variable de tipo de referencia tendrá algún patrón de bits, no hay una relación fija entre los patrones de bits almacenados en tales variables y los objetos que identifican. No hay forma de que el código pueda extraer información de un objeto o una referencia a él, y luego determinar si otra referencia identificó el mismo objeto, a menos que el código se mantuviera o conociera una referencia que identificara el objeto original.


Ref denota si la función puede obtener el objeto en sí, o solo en su valor.

Pasar por referencia no está ligado a un idioma; es una estrategia de enlace de parámetros al lado de paso por valor, paso por nombre, paso por necesidad, etc.

Una nota al margen: el nombre de la clase TestRef es una opción horriblemente mala en este contexto;).


Si estás pasando un valor, sin embargo, las cosas son diferentes. Puede forzar que un valor se pase por referencia. Esto le permite pasar un número entero a un método, por ejemplo, y hacer que el método modifique el número entero en su nombre.


ref imita (o se comporta) como un área global solo para dos ámbitos:

  • Llamador
  • Callee.