method - ¿Cuál es el uso de "ref" para las variables de tipo de referencia en C#?
output parameter method c# (9)
Además de las respuestas existentes:
Como solicitó la diferencia de los 2 métodos: No hay varianza (ntra) cuando se usa ref
o out
:
class Foo { }
class FooBar : Foo { }
static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }
void Main()
{
Foo foo = null;
Bar(foo); // OK
Bar(ref foo); // OK
FooBar fooBar = null;
Bar(fooBar); // OK (covariance)
Bar(ref fooBar); // compile time error
}
Entiendo que si paso un valor-tipo ( int
, struct
, etc.) como parámetro (sin la palabra clave ref
), se pasa una copia de esa variable al método, pero si uso la palabra clave ref
una referencia a esa se pasa la variable, no una nueva.
Pero con tipos de referencia, como clases, incluso sin la palabra clave ref
, se pasa una referencia al método, no una copia. Entonces, ¿cuál es el uso de la palabra clave ref
con los tipos de referencia?
Toma por ejemplo:
var x = new Foo();
¿Cuál es la diferencia entre lo siguiente?
void Bar(Foo y) {
y.Name = "2";
}
y
void Bar(ref Foo y) {
y.Name = "2";
}
Cuando pasa un tipo de referencia con la palabra clave ref, pasa la referencia por referencia y el método que llama puede asignar un nuevo valor al parámetro. Ese cambio se propagará al alcance de la llamada. Sin ref, la referencia se pasa por valor, y esto no sucede.
C # también tiene la palabra clave ''out'', que se parece mucho a ref, excepto que con ''ref'', los argumentos deben inicializarse antes de llamar al método, y con ''out'' debe asignar un valor en el método de recepción.
Hay casos en los que desea modificar la referencia real y no el objeto al que se apunta:
void Swap<T>(ref T x, ref T y) {
T t = x;
x = y;
y = t;
}
var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);
Jon Skeet escribió un excelente artículo sobre el paso de parámetros en C #. Detalla claramente el comportamiento exacto y el uso de los parámetros de paso por valor, por referencia ( ref
) y por salida ( out
).
Aquí hay una cita importante de esa página en relación con los parámetros de ref
:
Los parámetros de referencia no pasan los valores de las variables utilizadas en la invocación del miembro de función; usan las variables mismas. En lugar de crear una nueva ubicación de almacenamiento para la variable en la declaración del miembro de función, se utiliza la misma ubicación de almacenamiento, por lo que el valor de la variable en el miembro de la función y el valor del parámetro de referencia siempre serán los mismos. Los parámetros de referencia necesitan el modificador de ref como parte de la declaración y la invocación, lo que significa que siempre está claro cuando se pasa algo por referencia.
Le permite modificar la referencia pasada. Ej.
void Bar()
{
var y = new Foo();
Baz(ref y);
}
void Baz(ref Foo y)
{
y.Name = "2";
// Overwrite the reference
y = new Foo();
}
También puede usar out si no le importa la referencia pasada:
void Bar()
{
var y = new Foo();
Baz(out y);
}
void Baz(out Foo y)
{
// Return a new reference
y = new Foo();
}
Muy bien explicado aquí: http://msdn.microsoft.com/en-us/library/s6938f28.aspx
Resumen del artículo:
Una variable de un tipo de referencia no contiene sus datos directamente; contiene una referencia a sus datos. Cuando pasa un parámetro de tipo de referencia por valor, es posible cambiar los datos apuntados por la referencia, como el valor de un miembro de la clase. Sin embargo, no puede cambiar el valor de la referencia en sí; es decir, no puede usar la misma referencia para asignar memoria para una nueva clase y hacer que persista fuera del bloque. Para hacer eso, pase el parámetro usando la palabra clave ref o out.
Otro grupo de código
class O
{
public int prop = 0;
}
class Program
{
static void Main(string[] args)
{
O o1 = new O();
o1.prop = 1;
O o2 = new O();
o2.prop = 2;
o1modifier(o1);
o2modifier(ref o2);
Console.WriteLine("1 : " + o1.prop.ToString());
Console.WriteLine("2 : " + o2.prop.ToString());
Console.ReadLine();
}
static void o1modifier(O o)
{
o = new O();
o.prop = 3;
}
static void o2modifier(ref O o)
{
o = new O();
o.prop = 4;
}
}
Puedes cambiar a qué foo
apunta usando y
:
Foo foo = new Foo("1");
void Bar(ref Foo y)
{
y = new Foo("2");
}
Bar(ref foo);
// foo.Name == "2"
Un parámetro en un método parece estar siempre pasando una copia, la pregunta es una copia de qué. Una copia es hecha por un constructor de copia para un objeto y dado que todas las variables son Objeto en C #, creo que este es el caso para todos ellos. Las variables (objetos) son como las personas que viven en algunas direcciones. Cambiamos las personas que viven en esas direcciones o podemos crear más referencias a las personas que viven en esas direcciones en la guía telefónica (hacer copias poco profundas). Entonces, más de un identificador puede referirse a la misma dirección. Los tipos de referencia desean más espacio, por lo que a diferencia de los tipos de valor que están directamente conectados por una flecha a su identificador en la pila, tienen valor para otra dirección en el montón (un espacio más grande para morar). Este espacio debe ser tomado del montón.
Tipo de valor: identificador (contiene valor = dirección del valor de la pila) ----> valor del tipo de valor
Tipo de referencia: identificador (contiene el valor = dirección del valor de la pila) ----> (contiene el valor = dirección del valor del montón) ----> valor del montón (más a menudo contiene direcciones a otros valores), imagina más flechas pegadas en diferentes Cómo llegar a Array [0], Array [1], array [2]
La única forma de cambiar un valor es seguir las flechas. Si una flecha se pierde / cambia en la forma en que el valor es inalcanzable.