parameter generate example comentarios c#

generate - ref vs out parameter c#



Cuándo usar en vs ref vs fuera (15)

¿Por qué alguna vez quieres usar?

¡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, se requiere que el método de llamada asigne un valor antes de que el método regrese ".

ejemplo:

Car car; SetUpCar(out car); car.drive(); // You know car is initialized.

Alguien me preguntó el otro día cuándo deberían usar la palabra clave del parámetro out lugar de ref . Mientras que (creo) entiendo la diferencia entre las palabras clave ref y out (que se ha preguntado anteriormente ) 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? out y no ref .

Ya que ref es más general, ¿por qué quieres usarlo? ¿Es solo azúcar sintáctica?


¿Cómo usar in o out o ref en C #?

  • Todas las palabras clave en C# tienen la misma funcionalidad pero con algunos límites .
  • in argumentos no pueden ser modificados por el método llamado.
  • ref argumentos de ref pueden ser modificados.
  • ref debe inicializarse antes de que la persona que llama la use. Puede leerse y actualizarse en el método.
  • out argumentos de out deben ser modificados por la persona que llama.
  • out argumentos deben ser inicializados en el método.
  • Las variables pasadas como in argumentos deben inicializarse antes de pasar en una llamada de método. Sin embargo, el método llamado no puede asignar un valor o modificar el argumento.

No puede usar las palabras clave de out , ref y out para los siguientes tipos de métodos:

  • Métodos async , que define utilizando el modificador async .
  • Métodos de iterador , que incluyen una yield return yield break o yield break .

A continuación se muestran algunas notas que saqué de este artículo de código de proyecto en C # Out Vs Ref

  1. Se debe usar solo cuando estamos esperando varias salidas de una función o un método. Un pensamiento sobre estructuras puede ser también una buena opción para el mismo.
  2. REF y OUT son palabras clave que dictan cómo se pasan los datos de la persona que llama a la persona que llama y viceversa.
  3. En REF los datos pasan de dos maneras. De la persona que llama a la persona que llama y viceversa.
  4. Los datos de entrada solo pasan de una manera de la persona a la que se llama. En este caso, si la persona que llama trató de enviar datos a la persona que llama, se pasará por alto / rechazará.

Si usted es una persona visual, vea este video de su tubo que demuestra la diferencia prácticamente https://www.youtube.com/watch?v=lYdcY5zulXA

La imagen de abajo muestra las diferencias más visualmente.


Básicamente, tanto ref como out para pasar objeto / valor entre métodos

La 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étodo

ref : 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?

  1. Aunque las palabras clave ref y out causan un comportamiento diferente en el tiempo de ejecución, no se consideran parte de la firma del método en el momento de la 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 elimina un argumento.

  2. No puede usar las palabras clave ref y out para los siguientes tipos de métodos:

    • Métodos asíncronos, que define utilizando el modificador asíncrono.
    • Métodos de iterador, que incluyen una declaración de rendimiento o interrupción del rendimiento.
  3. Las propiedades no son variables y, por lo tanto, no se pueden pasar como parámetros.


Debe usar ref si planea leer y escribir en el parámetro. Necesitas usarlo si solo planeas escribir. En efecto, out es para cuando necesite más de un valor de retorno, o cuando no quiera usar el mecanismo de retorno normal para la salida (pero esto debería ser raro).

Existen mecánicas del lenguaje que ayudan en estos casos de uso. Ref parámetros de Ref deben haberse inicializado antes de pasarlos a un método (poniendo énfasis en el hecho de que son de lectura y escritura), y out parámetros de out no se pueden leer antes de que se les asigne un valor, y se garantiza que se escribieron en el Fin del método (poniendo énfasis en el hecho de que son de escritura solamente). Contravenir estos principios da como resultado un error en tiempo de compilación.

int x; Foo(ref x); // error: x is uninitialized void Bar(out int x) {} // error: x was not written to

Por ejemplo, int.TryParse devuelve un bool y acepta un parámetro out int :

int value; if (int.TryParse(numericString, out value)) { /* numericString was parsed into value, now do stuff */ } else { /* numericString couldn''t be parsed */ }

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 de la CLR decidieron optar por out aquí ya que no les importa lo que podría haber sido antes el int .

Para la ref , puede mirar en Interlocked.Increment . Interlocked.Increment :

int x = 4; Interlocked.Increment(ref x);

Interlocked.Increment incrementa atómicamente el valor de x . Ya que necesita leer x para incrementarlo, esta es una situación donde ref es más apropiado. Te importa totalmente lo que era x antes de que se pasara a Increment .

En la próxima versión de C #, incluso será posible declarar variables en out parámetros de out , agregando aún más énfasis en su naturaleza de solo salida:

if (int.TryParse(numericString, out int value)) { // ''value'' exists and was declared in the `if` statement } else { // conversion didn''t work, ''value'' doesn''t exist here }


Deberías agotarlo out menos que necesites ref .

Hace una gran diferencia cuando los datos deben ser agrupados, por ejemplo, a otro proceso, que puede ser costoso. Por lo tanto, debes 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 conservado) o desechado.

Como una diferencia menor, un parámetro de salida no necesita ser inicializado.

Ejemplo para out :

string a, b; person.GetBothNames(out a, out b);

donde GetBothNames es un método para recuperar dos valores de forma atómica, el método no cambiará el comportamiento, sea lo que sean a y b. 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:

string a = String.Empty, b = String.Empty; person.GetBothNames(ref a, ref b);

podría confundir a los lectores, porque parece que los valores iniciales de ayb son relevantes (aunque el nombre del método indicaría que no lo son).

Ejemplo para ref :

string name = textbox.Text; bool didModify = validator.SuggestValidName(ref name);

Aquí el valor inicial es relevante para el método.


Depende del contexto de compilación (Ver Ejemplo a continuación).

out y ref ambas indican la variable pasando por referencia, pero ref requiere 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 :

Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference.

De los documentos oficiales de MSDN:

The out keyword causes arguments to be passed by reference. This is similar to the ref keyword, except that ref requires that the variable be initialized before being passed

The ref keyword causes an argument to be passed by reference, not by value. The effect of passing by reference is that any change to the parameter in the method is reflected in the underlying argument variable in the calling method. The value of a reference parameter is always the same as the value of the underlying argument variable.

Podemos verificar que el out y el ref son de hecho iguales cuando se asigna el argumento:

Ejemplo CIL :

Considere el siguiente ejemplo

static class outRefTest{ public static int myfunc(int x){x=0; return x; } public static void myfuncOut(out int x){x=0;} public static void myfuncRef(ref int x){x=0;} public static void myfuncRefEmpty(ref int x){} // Define other methods and classes here }

en CIL, las instrucciones de myfuncOut y myfuncRef son idénticas a las esperadas.

outRefTest.myfunc: IL_0000: nop IL_0001: ldc.i4.0 IL_0002: starg.s 00 IL_0004: ldarg.0 IL_0005: stloc.0 IL_0006: br.s IL_0008 IL_0008: ldloc.0 IL_0009: ret outRefTest.myfuncOut: IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.0 IL_0003: stind.i4 IL_0004: ret outRefTest.myfuncRef: IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.0 IL_0003: stind.i4 IL_0004: ret outRefTest.myfuncRefEmpty: IL_0000: nop IL_0001: ret

nop : no operación, ldloc : carga local, stloc : pila local, ldarg : argumento de carga, bs.s : rama a destino ...

(Ver: Lista de instrucciones CIL )


Notas adicionales con respecto a C # 7:
En C # 7 no hay necesidad de predecir variables usando. Así que un código como este:

public void PrintCoordinates(Point p) { int x, y; // have to "predeclare" p.GetCoordinates(out x, out y); WriteLine($"({x}, {y})"); }

Puede escribirse así:

public void PrintCoordinates(Point p) { p.GetCoordinates(out int x, out int y); WriteLine($"({x}, {y})"); }

Fuente: Novedades en C # 7.


Puede usar la palabra clave out contexto en dos contextos (cada uno es un enlace a información detallada), como 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 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. Para usar un parámetro de out , tanto la definición del método como el método de llamada deben usar explícitamente la palabra clave de out . Por ejemplo: C #

class OutExample { static void Method(out int i) { i = 44; } static void Main() { int value; Method(out value); // value is now 44 } }

Aunque las variables pasadas como argumentos no tienen que ser inicializadas antes de ser pasadas, el método llamado debe asignar un valor antes de que el método regrese.

Aunque las palabras clave ref y out causan un comportamiento diferente en el tiempo de ejecución, no se consideran parte de la firma del método en el momento de la 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 elimina un argumento. El siguiente código, por ejemplo, no se compilará: C #

class CS0663_Example { // Compiler error CS0663: "Cannot define overloaded // methods that differ only on ref and out". public void SampleMethod(out int i) { } public void SampleMethod(ref int i) { } }

Sin embargo, se puede realizar una sobrecarga si un método toma un argumento ref o out y el otro no lo hace, como esto: C #

class OutOverloadExample { public void SampleMethod(int i) { } public void SampleMethod(out int i) { i = 5; } }

Las propiedades no son variables y, por lo tanto, no se pueden pasar como parámetros.

Para obtener información sobre cómo pasar matrices, consulte Pasar matrices utilizando ref y out (Guía de programación C #).

No puede usar las palabras clave ref y out para los siguientes tipos de métodos:

Async methods, which you define by using the async modifier. Iterator methods, which include a yield return or yield break statement.

Ejemplo

Declarar un método de out es útil cuando desea que un método devuelva varios valores. El siguiente ejemplo se utiliza para devolver tres variables con una sola llamada de método. Tenga en cuenta que el tercer argumento se asigna a nulo. Esto permite que los métodos devuelvan valores opcionalmente. DO#

class OutReturnExample { static void Method(out int i, out string s1, out string s2) { i = 44; s1 = "I''ve been returned"; s2 = null; } static void Main() { int value; string str1, str2; Method(out value, out str1, out str2); // value is now 44 // str1 is now "I''ve been returned" // str2 is (still) null; } }


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 en incorrecto.

Considere el uso de ref en un StringBuilder, que es un tipo de referencia:

private void Nullify(StringBuilder sb, string message) { sb.Append(message); sb = null; } // -- snip -- StringBuilder sb = new StringBuilder(); string message = "Hi Guy"; Nullify(sb, message); System.Console.WriteLine(sb.ToString()); // Output // Hi Guy

Como se adjunta a esto:

private void Nullify(ref StringBuilder sb, string message) { sb.Append(message); sb = null; } // -- snip -- StringBuilder sb = new StringBuilder(); string message = "Hi Guy"; Nullify(ref sb, message); System.Console.WriteLine(sb.ToString()); // Output // NullReferenceException


Tiene razón en que, semánticamente, ref proporciona funcionalidad tanto "in" como "out", mientras que out solo proporciona funcionalidad "out". Hay algunas cosas a considerar:

  1. 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 clave / valor como Dictionary<K,V> , donde tiene funciones como TryGetValue . Esta función toma un parámetro de out que contiene el valor que tendrá si se recupera. No tendría sentido que la persona que llama pase un valor a esta función, por lo que out se usa para garantizar que algún valor estará en la variable después de la llamada, incluso si no son datos "reales" (en el caso de TryGetValue donde la clave no está presente).
  2. out parámetros de out y ref se calculan de manera diferente al tratar con el código de interoperabilidad

Además, como punto de partida, es importante tener en cuenta que si bien los tipos de referencia y los tipos de valor difieren en la naturaleza de su valor, cada variable en su aplicación apunta a una ubicación de la 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 la memoria es otra ubicación de la 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 la ubicación de la memoria se copia. De cualquier manera, crea una copia de los datos contenidos en la variable. La única relevancia real que esto tiene se relaciona con la semántica de la tarea; 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 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ó.

Al pasar con la palabra clave ref dice que tanto la variable original como el parámetro de función apuntarán a la misma ubicación de memoria. Esto, de nuevo, afecta solo a la semántica de asignación. Si se asigna un nuevo valor a una de las variables, como los otros puntos apuntan a la misma ubicación de memoria, el nuevo valor se reflejará en el otro lado.


Un argumento pasado como referencia debe inicializarse antes de pasar al método, mientras que el parámetro out no necesita ser inicializado antes de pasar a un método.


Use para denotar que el parámetro no está siendo usado, solo establecido. 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.


out es una versión más restringida de ref .

En el cuerpo del método, debe asignar a todos out parámetros antes de abandonar el método. También se ignoran los valores asignados a un parámetro de out , mientras que ref requiere que se asignen.

Así que out te permite hacer:

int a, b, c = foo(out a, out b);

donde ref requeriría a y b para ser asignado.


Como suena:

out = solo inicializar / rellenar un parámetro (el parámetro debe estar vacío) devolverlo sin formato

ref = referencia, parámetro estándar (quizás con valor), pero la función puede modificarlo.