¿Cuál es mejor, valor de retorno o parámetro de salida?

Si queremos obtener un valor de un método, podemos usar el valor de retorno, como este:

public int GetValue(); 

o:

 public void GetValue(out int x); 

Realmente no entiendo las diferencias entre ellos, y entonces, no sé cuál es mejor. ¿Puedes explicarme esto?

Gracias.

Los valores devueltos casi siempre son la elección correcta cuando el método no tiene nada más que devolver. (De hecho, no puedo pensar en ningún caso en el que desee un método de vacío con un parámetro de out , si tuviera la opción. Los métodos de Deconstruct C # 7 para la Deconstruct apoyada en el lenguaje actúan como una muy rara excepción a Esta regla.)

Aparte de todo lo demás, impide que la persona que llama tenga que declarar la variable por separado:

 int foo; GetValue(out foo); 

vs

 int foo = GetValue(); 

Los valores de salida también impiden el encadenamiento de métodos de esta manera:

 Console.WriteLine(GetValue().ToString("g")); 

(De hecho, ese es también uno de los problemas con los establecedores de propiedades, y es por eso que el patrón del constructor utiliza métodos que devuelven el constructor, por ejemplo, myStringBuilder.Append(xxx).Append(yyy) .

Además, los parámetros de salida son un poco más difíciles de usar con la reflexión y, por lo general, también dificultan las pruebas. (Por lo general, se requiere más esfuerzo para facilitar la simulación de los valores de retorno que de los parámetros). Básicamente no hay nada en lo que pueda pensar que hagan más fácil

Devuelve los valores FTW.

EDITAR: en términos de lo que está pasando …

Básicamente, cuando pasa un argumento para un parámetro de “salida”, debe pasar una variable. (Los elementos de la matriz también se clasifican como variables.) El método que usted llama no tiene una “nueva” variable en su stack para el parámetro; usa su variable para el almacenamiento. Cualquier cambio en la variable es inmediatamente visible. Aquí hay un ejemplo que muestra la diferencia:

 using System; class Test { static int value; static void ShowValue(string description) { Console.WriteLine(description + value); } static void Main() { Console.WriteLine("Return value test..."); value = 5; value = ReturnValue(); ShowValue("Value after ReturnValue(): "); value = 5; Console.WriteLine("Out parameter test..."); OutParameter(out value); ShowValue("Value after OutParameter(): "); } static int ReturnValue() { ShowValue("ReturnValue (pre): "); int tmp = 10; ShowValue("ReturnValue (post): "); return tmp; } static void OutParameter(out int tmp) { ShowValue("OutParameter (pre): "); tmp = 10; ShowValue("OutParameter (post): "); } } 

Resultados:

 Return value test... ReturnValue (pre): 5 ReturnValue (post): 5 Value after ReturnValue(): 10 Out parameter test... OutParameter (pre): 5 OutParameter (post): 10 Value after OutParameter(): 10 

La diferencia está en el paso “post”, es decir, después de que se haya cambiado la variable local o el parámetro. En la prueba ReturnValue, esto no hace ninguna diferencia en la variable de value estático. En la prueba OutParameter, la variable de value se cambia por la línea tmp = 10;

En general, debería preferir un valor de retorno sobre un parámetro externo. Los params son un mal neccisario si te encuentras escribiendo código que necesita hacer 2 cosas. Un buen ejemplo de esto es el patrón Try (como Int32.TryParse).

Consideremos qué debería hacer la persona que llama de tus dos métodos. Para el primer ejemplo, puedo escribir esto …

 int foo = GetValue(); 

Tenga en cuenta que puedo declarar una variable y asignarla a través de su método en una línea. Para el segundo ejemplo, se ve así …

 int foo; GetValue(out foo); 

Ahora estoy obligado a declarar mi variable por adelantado y escribir mi código en dos líneas.

actualizar

Un buen lugar para mirar cuando se formula este tipo de preguntas es el .NET Framework Design Guidelines. Si tienes la versión del libro, entonces puedes ver las anotaciones de Anders Hejlsberg y otros sobre este tema (página 184-185), pero la versión en línea está aquí …

http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx

Si te encuentras que necesitas devolver dos cosas de una API, envolverlas en una estructura / clase sería mejor que un param externo.

Lo que es mejor, depende de tu situación particular. Una de las razones out las cuales existe es facilitar la devolución de múltiples valores desde una llamada a un método:

 public int ReturnMultiple(int input, out int output1, out int output2) { output1 = input + 1; output2 = input + 2; return input; } 

Entonces uno no es por definición mejor que el otro. Pero normalmente querrías usar un retorno simple, a menos que tengas la situación anterior por ejemplo.

EDITAR: Este es un ejemplo que demuestra una de las razones por las que existe la palabra clave. Lo anterior de ninguna manera debe considerarse una mejor práctica.

Hay una razón para utilizar un parámetro externo que no se ha mencionado anteriormente: el método de llamada está obligado a recibirlo. Si su método produce un valor que la persona que llama no debe descartar, convertirlo en un out obliga a la persona que llama a aceptarlo específicamente:

  Method1(); // Return values can be discard quite easily, even accidentally int resultCode; Method2(out resultCode); // Out params are a little harder to ignore 

Por supuesto, la persona que llama aún puede ignorar el valor en un param externo, pero usted ha llamado su atención sobre eso.

Esta es una necesidad rara; más a menudo, debe usar una excepción para un problema genuino o devolver un objeto con información de estado para un “FYI”, pero podría haber circunstancias donde esto es importante.

Es preferencia principalmente

Prefiero las devoluciones y si tiene varias devoluciones puede envolverlas en un resultado DTO

 public class Result{ public Person Person {get;set;} public int Sum {get;set;} } 

Casi siempre deberías usar un valor de retorno. los parámetros ‘ out ‘ crean un poco de fricción para muchas API, composicionalidad, etc.

La excepción más notable que viene a la mente es cuando quieres devolver múltiples valores (.Net Framework no tiene tuplas hasta 4.0), como con el patrón TryParse .

Solo puede tener un valor de retorno mientras que puede tener múltiples parámetros de salida.

Solo necesita considerar los parámetros en esos casos.

Sin embargo, si necesita devolver más de un parámetro de su método, probablemente desee ver lo que está devolviendo desde un enfoque OO y considerar si es mejor devolver un objeto o una estructura con estos parámetros. Por lo tanto, has vuelto a un valor de retorno nuevamente.

Preferiría lo siguiente en lugar de cualquiera de esos en este simple ejemplo.

 public int Value { get; private set; } 

Pero, son todos muy parecidos. Usualmente, uno solo usaría ‘out’ si necesitan pasar múltiples valores desde el método. Si desea enviar un valor dentro y fuera del método, uno elegiría ‘ref’. Mi método es el mejor, si solo devuelve un valor, pero si quiere pasar un parámetro y recuperar un valor, es probable que elija su primera opción.

Ambos tienen un propósito diferente y el comstackdor no los trata igual. Si su método necesita devolver un valor, entonces debe usar return. Out se usa cuando su método necesita devolver valores múltiples.

Si usa return, entonces los datos se escriben primero en la stack de métodos y luego en el método de la llamada. Mientras que en caso de out, se escribe directamente en la stack de métodos de llamada. No estoy seguro de si hay más diferencias.

No hay una diferencia real, los parámetros están en C # para permitir que el método devuelva más de un valor, eso es todo.

Sin embargo, hay algunas pequeñas diferencias, pero ninguna de ellas es realmente importante:

Usar el parámetro out lo obligará a usar dos líneas como:

 int n; GetValue(n); 

mientras utiliza el valor de retorno le permitirá hacerlo en una línea:

 int n = GetValue(); 

Otra diferencia (correcta solo para los tipos de valor y solo si C # no enmarca la función) es que usar el valor de retorno necesariamente hará una copia del valor cuando la función retorna mientras usa el parámetro OUT no necesariamente lo hará.

Como otros han dicho: valor de retorno, no fuera param.

¿Puedo recomendarle el libro “Framework Design Guidelines” (2nd ed)? Las páginas 184-185 cubren las razones para evitar los params. Todo el libro lo guiará en la dirección correcta en todo tipo de problemas de encoding .NET.

Aliado con Framework Design Guidelines es el uso de la herramienta de análisis estático, FxCop. Lo encontrará en los sitios de Microsoft como una descarga gratuita. Ejecute esto en su código comstackdo y vea lo que dice. Si se queja de cientos y cientos de cosas … ¡no entres en pánico! Mire con calma y cuidado lo que dice sobre cada caso. No te apresures a arreglar las cosas lo antes posible. Aprende de lo que te está diciendo. Te pondrás en el camino hacia el dominio.

Creo que uno de los pocos escenarios en los que sería útil sería cuando se trabaja con memoria no administrada, y quiere que sea obvio que el valor “devuelto” debe eliminarse manualmente, en lugar de esperar que se elimine por sí mismo. .

Además, los valores de retorno son compatibles con los paradigmas de diseño asincrónico.

No puede designar una función “async” si usa parámetros de ref o out.

En resumen, los valores de retorno permiten el encadenamiento del método, una syntax más limpia (al eliminar la necesidad de que el llamante declare variables adicionales) y permiten diseños asíncronos sin la necesidad de modificaciones sustanciales en el futuro.

El uso de la palabra clave out con un tipo de retorno de bool, a veces puede reducir la saturación del código y boost la legibilidad. (Principalmente cuando la información adicional en el param a menudo se ignora). Por ejemplo:

 var result = DoThing(); if (result.Success) { result = DoOtherThing() if (result.Success) { result = DoFinalThing() if (result.Success) { success = true; } } } 

vs:

 var result; if (DoThing(out result)) { if (DoOtherThing(out result)) { if (DoFinalThing(out result)) { success = true; } } } 

out es más útil cuando intentas devolver un objeto que declaras en el método.

Ejemplo

 public BookList Find(string key) { BookList book; //BookList is a model class _books.TryGetValue(key, out book) //_books is a concurrent dictionary //TryGetValue gets an item with matching key and returns it into book. return book; } 

el valor de retorno es el valor normal que devuelve su método.

Donde los parámetros out , well out y ref son 2 palabras clave de C #, permiten pasar variables como referencia .

La gran diferencia entre ref y out es que ref debe inicializarse antes y no