Entiendo (o al menos creo que lo hago) lo que significa pasar una instancia de una clase a un método por ref
versus no pasar por ref
. ¿Cuándo o en qué circunstancias se debe pasar una instancia de clase por ref
? ¿Existe una mejor práctica cuando se usa la palabra clave ref
para instancias de clase?C# ref uso de la palabra clave
Respuesta
La explicación más clara que he funcionado a través de los parámetros de salida y ref ... es Jon Skeet.
Él no entra en las "mejores prácticas", pero si usted entiende los ejemplos que le ha dado, usted sabrá cuando es necesario utilizarlas.
Todas las respuestas son muy útiles; sin embargo, estoy aceptando la respuesta de womp ya que aborda específicamente mi pregunta sobre "mejores prácticas". ¡Muchas gracias a todos! – CiaoRoma
No tengo ninguna duda de que Jon Skeet explica esto perfectamente en su sitio, pero esta respuesta no es más que un enlace y, como tal, se volverá inútil cuando el sitio detrás del enlace disminuya. – magnattic
La palabra clave ref
le permite pasar un argumento por referencia. Para los tipos de referencia, esto significa que se pasa la referencia real a un objeto (en lugar de una copia de esa referencia). Para los tipos de valor, esto significa que se pasa una referencia a la variable que contiene el valor de ese tipo.
Esto se utiliza para los métodos que necesitan devolver más de un resultado pero no devuelven un tipo complejo para encapsular esos resultados. Le permite pasar una referencia a un objeto en el método para que el método pueda modificar ese objeto.
Lo importante que debe recordar es que los tipos de referencia normalmente no se pasan por referencia, sino que se pasa una copia de una referencia. Esto significa que no está trabajando con la referencia real que se le pasó. Cuando usa ref
en una instancia de clase, está pasando la referencia real, por lo que todas las modificaciones a la misma (como establecerlo en null
) se aplicarán a la referencia original.
Para devolver más de un valor, debe usar 'out'. –
Que yo entiendo, pero ¿cuándo o bajo qué circunstancias necesitaría o querría usar la palabra clave ref para instancias de clase? Eso es lo que realmente me tiene perplejo. – CiaoRoma
Acabo de leer la respuesta de Shoham. Gracias por sus comentarios. – CiaoRoma
En pocas palabras, pasaría un valor como un parámetro ref
si desea que la función que está llamando pueda alterar el valor de esa variable.
Esto no es lo mismo que pasar una referencia tipo como parámetro de una función. En esos casos, aún está pasando por valor, pero el valor es como referencia. En el caso de pasar por ref
, se envía una referencia real a la variable; esencialmente, usted y la función a la que llama "comparten" la misma variable.
considerar lo siguiente:
public void Foo(ref int bar)
{
bar = 5;
}
...
int baz = 2;
Foo(ref baz);
En este caso, la variable baz
tiene un valor de 5, ya que se pasa por referencia. La semántica es completamente clara para los tipos de valores, pero no tan claros para los tipos de referencia.
public class MyClass
{
public int PropName { get; set; }
}
public void Foo(MyClass bar)
{
bar.PropName = 5;
}
...
MyClass baz = new MyClass();
baz.PropName = 2;
Foo(baz);
Como se esperaba, baz.PropName
habrá 5, ya que MyClass
es un tipo de referencia. Pero vamos a hacer esto:
public void Foo(MyClass bar)
{
bar = new MyClass();
bar.PropName = 5;
}
Con el mismo código de llamada, baz.PropName
permanecerán 2. Esto se debe a que a pesar de que MyClass
es un tipo de referencia, Foo
tiene su propia variable para bar
; bar
y baz
acaba de comenzar con el mismo valor, pero una vez que Foo
asigna un nuevo valor, son solo dos variables diferentes. Sin embargo, si hacemos esto:
public void Foo(ref MyClass bar)
{
bar = new MyClass();
bar.PropName = 5;
}
...
MyClass baz = new MyClass();
baz.PropName = 2;
Foo(ref baz);
vamos a terminar con PropName
siendo 5, desde que pasamos baz
por referencia, por lo que las dos funciones "compartir" la misma variable.
+1 ¡Excelentes y claros ejemplos! – Nate
Al pasar tipos de referencia (tipos no válidos) a un método, solo la referencia se pasa en ambos casos.Sin embargo, cuando se utiliza la palabra clave ref, el método puede ser llamado cambio la referencia.
Por ejemplo:
public void MyMethod(ref MyClass obj)
{
obj = new MyClass();
}
en otra parte:
MyClass x = y; // y is an instance of MyClass
// x points to y
MyMethod(ref x);
// x points to a new instance of MyClass
al llamar MyMethod (ref x), x apuntará al objeto recién creado después de la llamada al método. x ya no apunta al objeto original.
Este ejemplo necesita algo de trabajo; en su lugar, usaría la palabra clave out. –
Este ejemplo simplemente ilustra que el método llamado puede cambiar el valor. Al usar la palabra clave out, el método llamado no puede usar el parámetro que se pasó. Solo puede establecerlo. –
Cuando puede reemplazar el objeto original, debe enviarlo como ref
. Si solo es para salida y puede ser sin inicializar antes de llamar a la función, usará out
.
+1 para mencionar puede ser no inicializado y ref no puede. –
La mayoría de los casos de uso para pasar una variable de referencia por referencia implica la inicialización y la salida es más apropiada que la ref. Y compilan a la misma cosa (el compilador impone diferentes restricciones: las variables de referencia se inicializan antes de pasarlas y las variables de salida se inicializan en el método). Por lo tanto, el único caso en el que puedo pensar en dónde esto sería útil es en el que debe verificar una variable de referencia instanciada y es posible que deba reiniciarse en determinadas circunstancias.
Esto también podría ser necesario modificar una clase inmutable (como cadena) como señala R. Asaf
he encontrado que es fácil de ejecutar en problemas usando la palabra clave ref.
El método siguiente será modificar f incluso sin la palabra clave ref en la firma del método porque f es un tipo de referencia:
public void TrySet(Foo f,string s)
{
f.Bar = s;
}
En este segundo caso, sin embargo, la Foo original se ve afectado solamente por la primera línea de código, el resto del método de alguna manera crea y afecta solo una nueva variable local.
public void TryNew(Foo f, string s)
{
f.Bar = ""; //original f is modified
f = new Foo(); //new f is created
f.Bar = s; //new f is modified, no effect on original f
}
Sería bueno si el compilador le dio una advertencia en ese caso. Básicamente, lo que está haciendo es reemplazar la referencia que recibió por otra que hace referencia a un área de memoria diferente.
Es en realidad se desea reemplazar el objeto con una nueva instancia, utilizar la palabra clave ref:
public void TryNew(ref Foo f, string s)...
Pero no están disparando en el pie?Si la persona que llama no es consciente de que se crea un nuevo objeto, el siguiente código probablemente no funciona como es debido:
Foo f = SomeClass.AFoo;
TryNew(ref f, "some string"); //this will clear SomeClass.AFoo.Bar and then create a new distinct object
Y si se intenta "fijar" el problema añadiendo la línea:
SomeClass.AFoo = f;
Si el código contiene una referencia a SomeClass.AFoo en otro lugar, esa referencia se volverá inválida ...
Como regla general, probablemente deba evitar el uso de la nueva palabra clave para modificar un objeto que haya leído de otra clase o recibido como un parámetro en un método.
cuanto al uso de la palabra clave ref con los tipos de referencia, lo que puedo sugerir este enfoque:
1) No lo utilice si simplemente definiendo los valores del tipo de referencia, sino ser explícitos en sus funciones o parámetros nombres y en los comentarios:
public void SetFoo(Foo fooToSet, string s)
{
fooToSet.Bar = s;
}
2) Cuando hay una razón legítima para reemplazar el parámetro de entrada con una nueva, distinta ejemplo, utilizar una función con un valor de retorno en su lugar:
public Foo TryNew(string s)
{
Foo f = new Foo();
f.Bar = s;
return f;
}
Pero el uso de esta función todavía puede tener consecuencias no deseadas con el escenario SomeClass.AFoo:
SomeClass.AFoo = TryNew("some string");//stores a different object in SomeClass.AFoo
3) En algunos casos, como el ejemplo de cadena here es práctico el uso de params árbitro intercambio, pero al igual que en el caso 2 asegúrese de que el intercambio de las direcciones del objeto no afecte al resto de su código.
Dado que administra la asignación de memoria para usted, C# hace que sea muy fácil olvidar todo acerca de la administración de memoria, pero realmente ayuda a comprender cómo funcionan los punteros y las referencias. De lo contrario, puede introducir errores sutiles que son difíciles de encontrar.
Por último, este suele ser el caso en el que uno quisiera usar una función como memcpy, pero no hay tal cosa en C# que yo sepa.
- 1. C# palabra clave 'ref', rendimiento
- 2. palabra clave 'ref' y AppDomains
- 3. Cuándo pasar la palabra clave ref en
- 4. Objetos, parámetros y la palabra clave ref en C#
- 5. Usando un parámetro ref con la palabra clave this?
- 6. Problemas con la palabra clave ref. Pregunta muy novato!
- 7. Uso práctico de la palabra clave `stackalloc`
- 8. Uso de la palabra clave de bloqueo C#
- 9. C# Patrones de uso para la palabra clave "es"
- 10. C# utilizando la palabra clave, el uso adecuado de él
- 11. uso de la palabra clave "using" en C#
- 12. Uso práctico de la palabra clave parcial en C#
- 13. Uso de la palabra clave auto en C STL ++
- 14. Ilustrando el uso de la palabra clave volátil en C#
- 15. el uso de la palabra clave privada
- 16. instancia del uso de la palabra clave
- 17. ¿Cómo uso programáticamente la palabra clave "usar" en C#?
- 18. USO palabra clave en Mysql
- 19. C: Comportamiento de la palabra clave `const`
- 20. Palabra clave protegida C#
- 21. ¿Cómo uso una palabra clave C# como nombre de propiedad?
- 22. El uso de IsAssignableFrom y "es" palabra clave en C#
- 23. C# palabra clave virtual
- 24. C# - Palabra clave de uso + virtual anulación contra nuevo
- 25. ¿Cuál es el uso de la palabra clave volátil?
- 26. El uso de esta palabra clave Java
- 27. as3: uso de esta palabra clave
- 28. tipos de palabras clave y de referencia "REF"
- 29. Falta la palabra clave 'con' en C#
- 30. C++: estructura y la nueva palabra clave
Esto sería útil si alguna vez tuvo que revertir una lista vinculada fuera de una entrevista en microsoft. void Reverse (ref Node Root) y cuando configura Root, la Raíz de la persona que llama se actualizará. –
Como antiguo programador de lenguaje ensamblador, veo su punto. – CiaoRoma
Las instancias de clase siempre se pasan por referencia (mientras que la referencia se pasa por valor) La única razón para usar ref es manipular la referencia a la instancia de clase dentro de un método. –