¿Por qué los parámetros ''out'' en.NET son una mala idea?
(21)
¿Por qué los parámetros ''out'' en .NET son una mala idea?
Hace poco me preguntaron esto, pero no tenía una respuesta real además de complicar innecesariamente una aplicación. ¿Qué otras razones hay?
Bueno, no hay una respuesta clara para esto, pero el caso de uso simple para el parámetro out sería "Int.TryParse (" 1 ", out myInt)"
El trabajo del método XXX.TrayParse es, si convierte un valor de algún tipo, a otro tipo, le devuelve un indicador booleano para indicar el éxito o el fracaso de la conversión, que es una parte, la otra parte es el valor convertido, que se transmite por el parámetro out en ese método.
Este método TryParse se introdujo en .NET 2.0 para superar el hecho de que XXX.Parse realizará una excepción si la conversión falla y tiene que poner try / catch alrededor de la declaración.
Así que, básicamente, depende de lo que esté haciendo su método, y qué métodos están esperando los llamantes, si está haciendo un método que devuelve algún tipo de códigos de respuesta, entonces los parámetros de salida podrían usarse para llevar a cabo los resultados del método devuelto.
de todos modos, Microsoft dice "Evite usar parámetros", en su guía de diseño, consulte esta página msdn http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx
Creo que en algunos escenarios son una buena idea porque permiten devolver más de 1 objeto de una función, por ejemplo:
DateTime NewDate = new DateTime();
if (DateTime.TryParse(UserInput, out NewDate) == false) {
NewDate = DateTime.Now;
}
Muy útil :)
Ellos son una buena idea Porque a veces solo quieres devolver múltiples variables de un método, y no quieres crear una estructura de clase "pesada" para esto. La estructura de la clase de envoltura puede ocultar la forma en que fluye la información.
Yo uso esto para:
- Devuelve clave y datos IV en una llamada
- Dividir el nombre de una persona en diferentes entidades (primero, medio, apellido)
- Dividir la dirección
Es como le gusta decir al tipo Tanqueray: Todo con moderación.
Definitivamente me gustaría enfatizar el uso excesivo, ya que llevaría a "escribir c en c #" de manera similar a como se puede escribir java en Python (donde no se aceptan los patrones y modismos que hacen que el nuevo idioma sea especial, sino que simplemente pensando en su idioma antiguo y convirtiendo a la nueva sintaxis). Sin embargo, como siempre, si ayuda a que su código sea más elegante y tenga más sentido, agite.
Fuera - Los parámetros son una mala idea en mi opinión. Aumentan el riesgo de efectos secundarios y son difíciles de eliminar. La única buena solución son los resultados de las funciones y aquí está el problema: para los resultados de las funciones, debe crear para cada resultado complejo una tupla o un nuevo tipo. Ahora debería ser bastante fácil en c #, con tipos anónimos y genéricos.
Y por cierto: odio los efectos secundarios también.
No creo que lo sean Mal usarlos es una mala idea, pero eso vale para cualquier práctica / técnica de codificación.
Tendría que estar de acuerdo con GateKiller. No puedo imaginar que los parámetros sean demasiado malos si Microsoft los usara como parte de la biblioteca base. Pero, como con todas las cosas, mejor con moderación.
Un punto que no veo mencionado es que la palabra clave out también requiere que la persona que llama especifique out. Esto es importante ya que ayuda a asegurarse de que la persona que llama entiende que llamar a esta función modificará sus variables.
Esta es una razón por la que nunca me gustó usar referencias como parámetros de salida en C ++. La persona que llama puede llamar fácilmente a un método sin saber que su parámetro se modificará.
Yo diría que la respuesta que dio es la mejor que hay. Siempre que sea posible, debe diseñar alejados de out
parámetros, ya que generalmente hace que el código sea innecesariamente complejo.
Pero esto es cierto para casi cualquier patrón. Si no es necesario, no lo use.
Yo diría que tu respuesta es perfecta; generalmente es una complicación innecesaria y generalmente hay un diseño más simple. La mayoría de los métodos con los que trabajas en .NET no modifican sus parámetros de entrada, por lo que tener un método único que utilice la sintaxis es un poco confuso. El código se vuelve un poco menos intuitivo, y en el caso de un método mal documentado, no tenemos forma de saber qué hace el método para el parámetro de entrada.
Además, las firmas de métodos sin parámetros desencadenarán una violación de Code Analysis / FxCop, si eso es una métrica que te interese. En la mayoría de los casos, hay una mejor manera de lograr la intención de un método que utiliza un parámetro de "salida" y el método se puede refactorizar para devolver la información interesante.
el '' out
'' es genial!
Hace una declaración clara de que el parámetro contiene un valor que debe devolver el método.
El compilador también lo obliga a inicializarlo (si lo usamos como parámetro de retorno, debe inicializarse).
Bueno, no son una mala idea, creo. Dictionary<K, V>
tiene un método TryGetValue
, que es un muy buen ejemplo de por qué los parámetros de salida a veces son algo muy agradable de tener.
No debe abusar de esta característica, por supuesto, pero no es una mala idea por definición. Especialmente no en C # donde tienes que escribir la palabra clave out
en la declaración de función y llamada, lo que hace obvio lo que está sucediendo.
Yo diría que la razón para evitarlo sería porque es más simple tener un método de procesar datos y devolver una pieza lógica de datos. Si necesita devolver más datos, puede ser candidato para una mayor abstracción o formalización del valor de retorno.
Una excepción es si los datos devueltos son algo terciarios, como un bool nullable. Puede ser verdadero / falso o indefinido. Un parámetro de salida puede ayudar a resolver una idea similar para otros tipos lógicos.
Otro que uso a veces es cuando necesitas obtener información a través de una interfaz que no permite el "mejor" método. Como usar bibliotecas de acceso a datos .Net y ORM por ejemplo. Cuando necesite devolver el gráfico de objeto actualizado (después de una ACTUALIZACIÓN) o un nuevo identificador generado por RDBMS (INSERTAR) más cuántas filas se vieron afectadas por la instrucción. SQL devuelve todo eso en una declaración, por lo que las llamadas múltiples a un método no funcionarán, ya que su capa de datos, biblioteca o ORM solo llama a un comando genérico INSERT / UPDATE y no puede almacenar valores para su posterior recuperación.
Las prácticas ideales, como nunca utilizar listas de parámetros dinámicos, o parámetros de salida, no siempre son prácticas todo el tiempo. De nuevo, solo piénselo dos veces si un parámetro out es la forma correcta de hacerlo. Si es así, ve por eso. (¡Pero asegúrese de documentarlo bien!)
La palabra clave out es necesaria (consulte SortedDictionart.TryGetValue
). Implica pasar por referencia y también le dice al compilador que lo siguiente:
int value;
some_function (out value);
está bien y que some_function
no está utilizando un valor unificado que normalmente sería un error.
Algunos lenguajes fuera de .NET los usan como macros de "no hacer nada" que simplemente le dan al programador información acerca de cómo se usan los parámetros en la función.
No creo que haya una razón real aunque no la haya visto tan seguido (aparte de las llamadas P / Invoke ).
Si te importa escribir un código confiable adoptando la inmutabilidad y eliminando los efectos secundarios, entonces los parámetros son una idea absolutamente terrible. Te obliga a crear variables mutables solo para lidiar con ellas. (No es que C # sea compatible con las variables de nivel de método de solo lectura de todos modos (al menos en la versión que estoy usando, 3.5)).
En segundo lugar, reducen la composicionalidad de las funciones al obligar al desarrollador a configurar y tratar con las variables que reciben los valores de salida. Esta es una ceremonia molesta. No se puede ir y componer expresiones usándolas con algo que se asemeje a la facilidad. Por lo tanto, el código que llama a estas funciones rápidamente se convierte en un gran desastre imperativo, proporcionando muchos lugares para que los errores se oculten.
La redacción de la pregunta es del "¿Has dejado de golpear a tu esposa?" variedad: supone que los parámetros son necesariamente una mala idea. Hay casos en los que se pueden abusar de los parámetros, pero ...
En realidad encajan muy bien en el lenguaje C #. Son como los parámetros de referencia , excepto que se garantiza que el método le asigna un valor y que la persona que llama no necesita inicializar la variable.
Los valores de retorno normales para las funciones se insertan en la pila donde se llaman y salen. Cuando suministra un parámetro de salida , le está dando al método una dirección de memoria específica para insertar el resultado. Esto también permite valores de devolución múltiples, aunque usar una estructura a menudo tiene más sentido.
Son maravillosos para el patrón TryParse y también proporcionan metadatos para otras cosas, como en el caso de SQL-CLR, donde los parámetros de salida se asignan a los parámetros de una firma de procedimiento almacenado.
Creo que la razón principal es "... Aunque los valores de retorno son comunes y muy utilizados, la aplicación correcta de los parámetros de salida y ref requiere habilidades intermedias de diseño y codificación . Los arquitectos de la biblioteca que diseñan para una audiencia general no deben esperar que los usuarios dominen el trabajo con parámetros de salida o ref. "
Por favor, lea más en: http://msdn.microsoft.com/en-us/library/ms182131.aspx
No siempre es una mala idea usar los parámetros. Por lo general, para el código que intenta crear un objeto basado en alguna forma de entrada, es una buena idea proporcionar un método Try sin parámetros y un valor de retorno booleano, no forzar al consumidor del método para que intente interceptar bloques por todas partes, sin mencionar el mejor rendimiento. Ejemplo:
bool TryGetSomeValue(out SomeValue value, [...]);
este es un caso donde los parámetros son una buena ideea.
Otro caso es donde desea evitar la costosa estructura grande que pasa entre los métodos. Por ejemplo:
void CreateNullProjectionMatrix(out Matrix matrix);
esta versión evita la costosa copia de estructuras.
Pero, a menos que sea necesario por una razón específica, se debe evitar.
Simplemente arruinan la semántica de un método / función un poco. Un método normalmente debe tomar un montón de cosas, y escupir una cosa. Al menos, así es como está en la mente de la mayoría de los programadores (creo).