Si queremos obtener un valor de un método, podemos usar cualquier valor de retorno, como este:
public int GetValue();
o:
public void GetValue(out int x);
Realmente no entiendo las diferencias entre ellos y, por lo tanto, no sé cuál es mejor. ¿Me puedes explicar esto?
Gracias.
Tuple
si lo desea, pero el consenso general es que si necesita devolver más de una cosa, las cosas generalmente están relacionadas de alguna manera y esa relación generalmente se expresa mejor como una clase.return Tuple.Create(x, y, z);
¿No es eso feo? Además, es tarde en el día tenerlos presentados a nivel de idioma. La razón por la que no crearía una clase para devolver valores de un parámetro ref / out es porque los parámetros ref / out solo tienen sentido para grandes estructuras mutables (como matrices) o valores opcionales, y este último es discutible.Tuple<>
tuplas .NET y C #. Solo deseaba que C # permitiera la devolución de tipos anónimos de métodos con compiladores que infieren tipos (comoauto
en Dlang).Respuestas:
Los valores de retorno son casi siempre 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 alguna vez quisiera un método nulo con un
out
parámetro, si tuviera la opción. LosDeconstruct
métodos de C # 7 para la deconstrucción basada en el lenguaje actúan como una excepción muy, muy rara a esta regla .)Aparte de cualquier otra cosa, evita que la persona que llama tenga que declarar la variable por separado:
vs
Los valores de salida también evitan el encadenamiento de métodos de esta manera:
(De hecho, ese es uno de los problemas con los establecedores de propiedades también, y es por eso que el patrón del generador utiliza métodos que devuelven el generador, por ejemplo
myStringBuilder.Append(xxx).Append(yyy)
).Además, los parámetros externos 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 hace un mayor esfuerzo para facilitar la burla de los valores de retorno que los parámetros). Básicamente no hay nada en lo que pueda pensar que hagan más fácil ...
Valores de retorno FTW.
EDITAR: en términos de lo que está pasando ...
Básicamente, cuando se pasa en un argumento para un parámetro "out", que tiene que pasar en una variable. (Los elementos de la matriz también se clasifican como variables). El método que llama no tiene una variable "nueva" en su pila para el parámetro: utiliza su variable para el almacenamiento. Cualquier cambio en la variable es inmediatamente visible. Aquí hay un ejemplo que muestra la diferencia:
Resultados:
La diferencia está en el paso "post", es decir, después de que la variable o parámetro local ha cambiado. En la prueba ReturnValue, esto no hace ninguna diferencia con la
value
variable estática . En la prueba OutParameter, lavalue
variable cambia la líneatmp = 10;
fuente
Dictionary.TryGetValue
es aplicable aquí, ya que no es un método nulo. ¿Puedes explicar por qué quieres un parámetro en lugar de un valor de retorno? (Incluso , preferiría un valor de retorno que contenga toda la información de salida, personalmente. Vea NodaTime's para ver un ejemplo de cómo lo habría diseñado.)out
TryGetValue
ParseResult<T>
out
parámetro, simplemente no puede hacer nada con el valor.Lo que es mejor, depende de su situación particular. Una de las razones que
out
existen es para facilitar la devolución de múltiples valores de una llamada a método:Entonces, uno no es por definición mejor que el otro. Pero, por lo general, querrá usar un retorno simple, a menos que tenga la situación anterior, por ejemplo.
EDITAR: Esta es una muestra que demuestra una de las razones por las que existe la palabra clave. Lo anterior no se debe considerar como una mejor práctica.
fuente
En general, debería preferir un valor de retorno sobre un parámetro de salida. Los params son un mal necesario si te encuentras escribiendo un código que necesita hacer 2 cosas. Un buen ejemplo de esto es el patrón Try (como Int32. TryParse).
Consideremos lo que la persona que llama de sus dos métodos tendría que hacer. Para el primer ejemplo, puedo escribir esto ...
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í ...
Ahora me veo obligado a declarar mi variable por adelantado y escribir mi código en dos líneas.
actualizar
Un buen lugar para mirar al hacer este tipo de preguntas son las Pautas de diseño de .NET Framework. Si tiene la versión del libro, puede 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 necesita devolver dos cosas de una API, entonces envolverlas en una estructura / clase sería mejor que un parámetro externo.
fuente
Hay una razón para usar un
out
parámetro que aún no se ha mencionado: el método de llamada está obligado a recibirlo. Si su método produce un valor que la persona que llama no debe descartar, lo queout
obliga a la persona que llama a aceptarlo específicamente:Por supuesto, la persona que llama aún puede ignorar el valor en un
out
parámetro, pero usted ha llamado su atención.Esta es una necesidad rara; con mayor frecuencia, 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 en las que esto sea importante.
fuente
Es preferencia principalmente
Prefiero devoluciones y si tiene devoluciones múltiples, puede envolverlas en un resultado DTO
fuente
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 de un enfoque OO y considerar si es mejor devolver un objeto o una estructura con estos parámetros. Por lo tanto, vuelve a un valor de retorno nuevamente.
fuente
Casi siempre debe usar un valor de retorno. '
out
' los parámetros crean un poco de fricción para muchas API, composición, etc.La excepción más notable que viene a la mente es cuando desea devolver múltiples valores (.Net Framework no tiene tuplas hasta 4.0), como con el
TryParse
patrón.fuente
Preferiría lo siguiente en lugar de cualquiera de los de este simple ejemplo.
Pero, todos son muy parecidos. Por lo general, uno solo usaría 'out' si necesitan pasar múltiples valores del 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 está devolviendo un valor, pero si desea pasar un parámetro y recuperar un valor, es probable que elija su primera opción.
fuente
Creo que uno de los pocos escenarios en los que sería útil sería trabajar con memoria no administrada, y desea que sea obvio que el valor "devuelto" debe eliminarse manualmente, en lugar de esperar que se elimine por sí solo. .
fuente
Además, los valores de retorno son compatibles con paradigmas de diseño asíncrono.
No puede designar una función "asíncrona" si usa parámetros ref o out.
En resumen, los valores de retorno permiten el encadenamiento de métodos, una sintaxis más limpia (al eliminar la necesidad de que la persona que llama declare variables adicionales) y permiten diseños asincrónicos sin la necesidad de modificaciones sustanciales en el futuro.
fuente
Ambos tienen un propósito diferente y el compilador no los trata de la misma manera. Si su método necesita devolver un valor, debe usar return. Out se usa cuando su método necesita devolver múltiples valores.
Si usa return, los datos se escriben primero en la pila de métodos y luego en los métodos de llamada. Si bien en caso de salida, se escribe directamente en la pila de métodos de llamada. No estoy seguro si hay más diferencias.
fuente
Como han dicho otros: 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 codificación .NET.
Aliado con las Pautas de diseño del marco está el uso de la herramienta de análisis estático, FxCop. Encontrará esto en los sitios de Microsoft como una descarga gratuita. Ejecute esto en su código compilado y vea lo que dice. Si se queja de cientos y cientos de cosas ... ¡no se asuste! 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. Serás puesto en el camino hacia el dominio.
fuente
El uso de la palabra clave out con un tipo de retorno de bool, a veces puede reducir la hinchazón de código y aumentar la legibilidad. (Principalmente cuando a menudo se ignora la información adicional en el parámetro de salida). Por ejemplo:
vs:
fuente
No hay diferencia real. Los parámetros de salida están en C # para permitir que el método devuelva más de un valor, eso es todo.
Sin embargo, existen algunas pequeñas diferencias, pero ninguna de ellas es realmente importante:
Usar el parámetro lo obligará a usar dos líneas como:
mientras usa el valor de retorno le permitirá hacerlo en una línea:
Otra diferencia (corregir solo para los tipos de valor y solo si C # no incluye la función en línea) es que el uso del valor de retorno necesariamente hará una copia del valor cuando la función regrese, mientras que el uso del parámetro OUT no necesariamente lo hará.
fuente
out es más útil cuando intenta devolver un objeto que declara en el método.
Ejemplo
fuente
El valor de retorno es el valor normal que devuelve su método.
Donde como parámetro 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 out no
fuente
Sospecho que no voy a echar un vistazo a esta pregunta, pero soy muy programador experimentado y espero que algunos de los lectores más abiertos presten atención.
Creo que se adapta mejor a los lenguajes de programación orientados a objetos para que sus procedimientos de retorno de valor (VRP) sean deterministas y puros.
'VRP' es el nombre académico moderno para una función que se llama como parte de una expresión y tiene un valor de retorno que reemplaza teóricamente la llamada durante la evaluación de la expresión. Por ejemplo, en una declaración como
x = 1 + f(y)
la funciónf
está sirviendo como un VRP.'Determinista' significa que el resultado de la función depende solo de los valores de sus parámetros. Si lo vuelve a llamar con los mismos valores de parámetro, seguramente obtendrá el mismo resultado.
'Puro' significa que no hay efectos secundarios: llamar a la función no hace nada excepto calcular el resultado. Esto puede interpretarse en el sentido de no importante efectos secundarios , en la práctica, por lo que si el VRP emite un mensaje de depuración cada vez que se llama, por ejemplo, eso probablemente se puede ignorar.
Por lo tanto, si, en C #, su función no es determinista y pura, le digo que debe hacerla una
void
función (en otras palabras, no un VRP), y cualquier valor que necesite devolver debe devolverse en unoout
o en unref
parámetro.Por ejemplo, si tiene una función para eliminar algunas filas de una tabla de base de datos y desea que devuelva el número de filas que eliminó, debe declararlo de la siguiente manera:
public void DeleteBasketItems(BasketItemCategory category, out int count);
Si a veces desea llamar a esta función pero no obtener la
count
, siempre puede declarar una sobrecarga.Es posible que desee saber por qué este estilo se adapta mejor a la programación orientada a objetos. En términos generales, se ajusta a un estilo de programación que podría llamarse (un poco impreciso) 'programación de procedimientos', y es un estilo de programación de procedimientos que se adapta mejor a la programación orientada a objetos.
¿Por qué? El modelo clásico de los objetos es que tienen propiedades (también conocidos como atributos), y usted interroga y manipula el objeto (principalmente) mediante la lectura y actualización de esas propiedades. Un estilo de programación de procedimientos tiende a facilitarlo, ya que puede ejecutar código arbitrario entre operaciones que obtienen y establecen propiedades.
La desventaja de la programación de procedimientos es que, debido a que puede ejecutar código arbitrario por todas partes, puede obtener algunas interacciones muy obtusas y vulnerables a los errores a través de variables globales y efectos secundarios.
Entonces, simplemente, es una buena práctica señalar a alguien que lee su código que una función podría tener efectos secundarios al hacer que no devuelva ningún valor.
fuente
_
símbolo de descarte para ignorar un parámetro de salida, por ejemplo: DeleteBasketItems (category, out _);