Alguien me preguntó el otro día cuándo deberían usar la palabra clave parámetro en out
lugar de ref
. Si bien (creo) entiendo la diferencia entre las palabras clave ref
y out
(que se ha preguntado antes ) y la mejor explicación parece ser que ref
== in
y out
, cuáles son algunos ejemplos (hipotéticos o de código) donde siempre debería usar out
y no ref
.
Como ref
es más general, ¿por qué quieres usarlo out
? ¿Es solo azúcar sintáctico?
out
no se puede leer antes de asignarla.ref
no tiene esta restricción Entonces ahí está eso.ref
es para entrada / salida, mientras queout
es un parámetro solo de salida.out
variables tienen que ser asignadas en la función.Respuestas:
Debe usar a
out
menos que lo necesiteref
.Hace una gran diferencia cuando los datos necesitan ser ordenados, por ejemplo, a otro proceso, que puede ser costoso. Por lo tanto, debe evitar calcular el valor inicial cuando el método no lo utiliza.
Más allá de eso, también muestra al lector de la declaración o la llamada si el valor inicial es relevante (y potencialmente preservado), o desechado.
Como una diferencia menor, no es necesario inicializar un parámetro de salida.
Ejemplo para
out
:donde GetBothNames es un método para recuperar dos valores atómicamente, el método no cambiará el comportamiento sean cuales sean ayb. Si la llamada va a un servidor en Hawai, copiar los valores iniciales de aquí a Hawai es una pérdida de ancho de banda. Un fragmento similar usando ref:
podría confundir a los lectores, porque parece que los valores iniciales de a y b son relevantes (aunque el nombre del método indicaría que no lo son).
Ejemplo para
ref
:Aquí el valor inicial es relevante para el método.
fuente
ref
los valores predeterminados.out
parámetro, se requiere que el método de llamada asigne un valor antes de que el método regrese. - No tiene que hacer nada con un parámetro de referencia.Úselo para denotar que el parámetro no se está utilizando, solo se establece. Esto ayuda a la persona que llama a comprender que siempre está inicializando el parámetro.
Además, ref y out no son solo para tipos de valor. También le permiten restablecer el objeto al que hace referencia un tipo de referencia dentro de un método.
fuente
out
los parámetros se tratan como no asignados al ingresar a la función. No podrá inspeccionar su valor hasta que haya asignado definitivamente algún valor; no hay forma de usar el valor que tenía el parámetro cuando se llamó a la función.Tiene razón en que, semánticamente,
ref
proporciona la funcionalidad "dentro" y "fuera", mientras queout
solo proporciona la funcionalidad "fuera". Hay algunas cosas a considerar:out
requiere que el método que acepta el parámetro DEBE, en algún momento antes de regresar, asignar un valor a la variable. Encontrará este patrón en algunas de las clases de almacenamiento de datos de clave / valorDictionary<K,V>
, donde tiene funciones comoTryGetValue
. Esta función toma unout
parámetro que contiene cuál será el valor si se recupera. No tendría sentido que la persona que llama transfiera un valor a esta función, por lo queout
se utiliza para garantizar que algún valor estará en la variable después de la llamada, incluso si no son datos "reales" (en el caso deTryGetValue
donde La clave no está presente).out
y losref
parámetros se ordenan de manera diferente cuando se trata de código de interoperabilidadAdemás, como comentario aparte, es importante tener en cuenta que si bien los tipos de referencia y los tipos de valor difieren en la naturaleza de su valor, están disponibles en ambos lados, pero eso se debe a que la variable real es solo un puntero a otra ubicación de memoria; el contenido de la variable, la ubicación de la memoria, en realidad no cambió. cada variable en su aplicación apunta a una ubicación de memoria que contiene un valor , incluso para los tipos de referencia. Simplemente sucede que, con los tipos de referencia, el valor contenido en esa ubicación de memoria es otroubicación de memoria Cuando pasa valores a una función (o realiza cualquier otra asignación de variable), el valor de esa variable se copia en la otra variable. Para los tipos de valor, eso significa que se copia todo el contenido del tipo. Para los tipos de referencia, eso significa que se copia la ubicación de la memoria. De cualquier manera, crea una copia de los datos contenidos en la variable. La única relevancia real que tiene esto tiene que ver con la semántica de asignación; cuando se asigna una variable o se pasa por valor (el valor predeterminado), cuando se realiza una nueva asignación a la variable original (o nueva), no afecta a la otra variable. En el caso de los tipos de referencia, sí, los cambios realizados en la instancia
Al pasar con la
ref
palabra clave se dice que tanto la variable original como el parámetro de la función en realidad apuntarán a la misma ubicación de memoria. Esto, nuevamente, afecta solo la semántica de asignación. Si se asigna un nuevo valor a una de las variables, como el otro apunta a la misma ubicación de memoria, el nuevo valor se reflejará en el otro lado.fuente
TryGetValue
uso correctoref
y noout
explícito en el caso de no encontrar la clave.Depende del contexto de compilación (ver el ejemplo a continuación).
out
yref
ambos denotan el paso de variables por referencia, peroref
requieren que la variable se inicialice antes de pasar, lo que puede ser una diferencia importante en el contexto de Marshaling (Interop: UmanagedToManagedTransition o viceversa)MSDN advierte :
De los documentos oficiales de MSDN:
out
:ref
:Podemos verificar que la salida y la referencia son las mismas cuando se asigna el argumento:
Ejemplo de CIL :
Considere el siguiente ejemplo
en CIL, las instrucciones de
myfuncOut
ymyfuncRef
son idénticas a las esperadas.nop : sin operación, ldloc : carga local, stloc : pila local, ldarg : argumento de carga, bs.s : rama a destino ...
(Ver: Lista de instrucciones CIL )
fuente
A continuación hay algunas notas que extraje de este artículo de codeproject en C # Out Vs Ref
Si eres una persona visual, mira este video de yourtube que demuestra la diferencia prácticamente https://www.youtube.com/watch?v=lYdcY5zulXA
La imagen de abajo muestra las diferencias más visualmente
fuente
one-way
, lostwo-way
términos pueden ser mal utilizados aquí. En realidad, ambos son bidireccionales, sin embargo, sus comportamientos conceptuales difieren en las referencias y valores de losDebe usarlo
ref
si planea leer y escribir en el parámetro. Debe usarloout
si solo planea escribir. En efecto,out
es para cuando necesitaría más de un valor de retorno, o cuando no desea utilizar el mecanismo de retorno normal para la salida (pero esto debería ser raro).Existen mecanismos de lenguaje que ayudan a estos casos de uso.
Ref
los parámetros deben haberse inicializado antes de pasar a un método (haciendo hincapié en el hecho de que son de lectura-escritura), y losout
parámetros no pueden leerse antes de que se les asigne un valor, y se garantiza que se han escrito al final de el método (enfatizando el hecho de que son solo de escritura). Contravenir estos principios da como resultado un error en tiempo de compilación.Por ejemplo,
int.TryParse
devuelvebool
ay acepta unout int
parámetro:Este es un claro ejemplo de una situación en la que necesita generar dos valores: el resultado numérico y si la conversión fue exitosa o no. Los autores del CLR decidieron optar por
out
aquí ya que no les importa lo queint
podría haber sido antes.Para
ref
, puedes mirarInterlocked.Increment
:Interlocked.Increment
incrementa atómicamente el valor dex
. Como necesita leerx
para incrementarlo, esta es una situación en la queref
es más apropiado. Te preocupas totalmente por lo quex
era antes de que fuera pasadoIncrement
.En la próxima versión de C #, incluso será posible declarar variables en los
out
parámetros, agregando aún más énfasis en su naturaleza de solo salida:fuente
out
parámetros no necesariamente se han inicializado, por lo que el compilador no le permitirá leer unout
parámetro hasta que haya escrito algo en él.nameOut
suif
declaración porque no se le asignó nada antes.out
es una versión más restrictiva deref
.En el cuerpo de un método, debe asignar a todos los
out
parámetros antes de abandonar el método. Tambiénout
se ignoran los valores asignados a un parámetro, mientras que seref
requiere que se asignen.Entonces
out
te permite hacer:donde
ref
requeriría que se asignen ayb.fuente
out
es la versión menos restringida.ref
tiene "Condición previa: variable se asignaron claramente, posterior: variable se asignaron claramente", mientras queout
sólo ha `Condición posterior:. variable es definitivamente asignado" (Y como era de esperar, se requiere más de una implementación de la función con un menor número de condiciones previas)Como suena:
a cabo = Sólo initialize / llenar un parámetro (el parámetro debe estar vacío) devuélvalo a cabo llanura
ref = referencia, parámetros estándar (tal vez con el valor), pero la función puede modifiy ella.
fuente
Puede usar la
out
palabra clave contextual en dos contextos (cada uno es un enlace a información detallada), como un modificador de parámetros o en declaraciones de parámetros de tipo genérico en interfaces y delegados. Este tema trata sobre el modificador de parámetros, pero puede ver este otro tema para obtener información sobre las declaraciones de parámetros de tipo genérico.La
out
palabra clave hace que los argumentos se pasen por referencia. Esto es como laref
palabra clave, excepto queref
requiere que la variable se inicialice antes de pasarla. Para usar unout
parámetro, tanto la definición del método como el método de llamada deben usar explícitamente laout
palabra clave. Por ejemplo: C #Aunque las variables pasaron como
out
argumentos no tienen que inicializarse antes de pasarlas, se requiere que el método llamado asigne un valor antes de que el método regrese.Aunque las palabras clave
ref
yout
provocan un comportamiento de tiempo de ejecución diferente, no se consideran parte de la firma del método en tiempo de compilación. Por lo tanto, los métodos no se pueden sobrecargar si la única diferencia es que un método toma unref
argumento y el otro toma unout
argumento. El siguiente código, por ejemplo, no se compilará: C #Sin embargo, se puede realizar una sobrecarga si un método toma un argumento
ref
oout
y el otro no usa ninguno de estos, de la siguiente manera: C #Las propiedades no son variables y, por lo tanto, no se pueden pasar como
out
parámetros.Para obtener información sobre cómo pasar matrices, consulte Pasar matrices usando
ref
yout
(Guía de programación de C #).No puede usar las palabras clave
ref
yout
para los siguientes tipos de métodos:Ejemplo
Declarar un
out
método es útil cuando desea que un método devuelva varios valores. El siguiente ejemplo se usaout
para devolver tres variables con una sola llamada al método. Tenga en cuenta que el tercer argumento se asigna a nulo. Esto permite que los métodos devuelvan valores opcionalmente. C#fuente
¿Cómo usar
in
oout
oref
en C #?C#
tienen la misma funcionalidad pero con algunos límites .in
Los argumentos no pueden ser modificados por el método llamado.ref
Los argumentos pueden ser modificados.ref
debe inicializarse antes de ser utilizado por la persona que llama, puede leerse y actualizarse en el método.out
los argumentos deben ser modificados por la persona que llama.out
los argumentos deben inicializarse en el métodoin
argumentos deben inicializarse antes de pasarlas en una llamada al método. Sin embargo, el método llamado puede no asignar un valor o modificar el argumento.No se pueden utilizar los
in
,ref
yout
palabras clave para los siguientes tipos de métodos:async
modificador.yield return
oyield break
.fuente
Solo para aclarar en el comentario de OP que el uso en ref y out es una "referencia a un tipo de valor o estructura declarada fuera del método", que ya se ha establecido de forma incorrecta.
Considere el uso de ref en un StringBuilder, que es un tipo de referencia:
Según lo dispuesto a esto:
fuente
Un argumento pasado como ref debe inicializarse antes de pasar al método, mientras que el parámetro out no necesita inicializarse antes de pasar a un método.
fuente
¡Para que otros sepan que la variable se inicializará cuando regrese del método llamado!
Como se mencionó anteriormente: "para un parámetro de salida, el método de llamada debe asignar un valor antes de que el método regrese ".
ejemplo:
fuente
Básicamente ambos
ref
yout
para pasar objeto / valor entre métodosLa palabra clave out hace que los argumentos se pasen por referencia. Esto es como la palabra clave ref, excepto que ref requiere que la variable se inicialice antes de pasarla.
out
: El argumento no se inicializa y debe inicializarse en el métodoref
: El argumento ya está inicializado y se puede leer y actualizar en el método.¿Cuál es el uso de "ref" para los tipos de referencia?
Puede cambiar la referencia dada a una instancia diferente.
¿Sabías?
Aunque las palabras clave ref y out provocan un comportamiento de tiempo de ejecución diferente, no se consideran parte de la firma del método en tiempo de compilación. Por lo tanto, los métodos no se pueden sobrecargar si la única diferencia es que un método toma un argumento ref y el otro saca un argumento out.
No puede usar las palabras clave ref y out para los siguientes tipos de métodos:
Las propiedades no son variables y, por lo tanto, no se pueden pasar como parámetros de salida.
fuente
Notas adicionales con respecto a C # 7:
en C # 7 no hay necesidad de predeclarar variables usando. Entonces un código como este:
Se puede escribir así:
Fuente: Novedades en C # 7.
fuente
Todavía siento la necesidad de un buen resumen, esto es lo que se me ocurrió.
Resumen,
Cuando estamos dentro de la función , así es como especificamos el control de acceso a datos variables ,
in
= Rout
= debe W antes de Rref
= R + WExplicación,
in
La función solo puede LEER esa variable.
out
La variable no debe inicializarse primero porque, la
función DEBE ESCRIBIRLA antes de LEER .
ref
La función puede LEER / ESCRIBIR a esa variable.
¿Por qué se llama así?
Centrándose en dónde se modifican los datos,
in
Los datos solo deben establecerse antes de ingresar la función (in).
out
Los datos solo deben establecerse antes de dejar la función (fuera).
ref
Los datos deben establecerse antes de ingresar la función (in).
Los datos se pueden configurar antes de dejar la función (fuera).
fuente
Cabe señalar que
in
es una palabra clave válida a partir de C # ver 7.2 :fuente