2009-09-16 14 views
8

Tanto en SQL como en C#, nunca me han gustado los parámetros de salida. Nunca pasé los parámetros ByRef en VB6, tampoco. Algo acerca de contar con los efectos secundarios para hacer algo solo me molesta.¿Qué pasa con los parámetros de salida?

Sé que son una forma de evitar el retorno de resultados múltiples de una función, pero un conjunto de filas en SQL o un tipo de datos complejo en C# y VB funcionan igual de bien, y me parecen más autodocumentados.

¿Hay algo de malo en mi forma de pensar, o hay recursos de fuentes autorizadas que me respalden? ¿Cuál es su opinión personal sobre esto y por qué? ¿Qué puedo decir a los colegas que quieren diseñar con parámetros de salida que puedan convencerlos de usar estructuras diferentes?

EDITAR: giro interesante: el parámetro de salida sobre el que hacía esta pregunta se utilizó en lugar de un valor de retorno. Cuando el valor de retorno es "ERROR", la persona que llama debe manejarlo como una excepción. Estaba haciendo eso pero no me gustó la idea. Un compañero de trabajo no fue informado de la necesidad de manejar esta condición y como resultado, se perdió una gran cantidad de dinero ya que el procedimiento falló en silencio.

+1

Esto es subjetivo y debería ser wiki de la comunidad para su existencia continua. Noto que ya hay un golpe cercano. No cerraré a menos que no lo marque CW. – Randolpho

+4

Qué sé, pero esto me parece una buena pregunta sobre las concesiones de diseño. – JeffH

+0

cambié las etiquetas para incluir referencias sql + vb en las preguntas – gbn

Respuesta

11

Bob Martin escribió sobre este código de limpieza. Los parámetros de salida rompen la idea fundamental de una función.

output = someMethod(input)

+0

Un proceso almacenado no es una función, pero entiendo que el razonamiento – gbn

+0

parece que el enlace a Bob Martin ahora está muerto. – PaulBinder

27

Los parámetros de salida pueden ser un olor a código que indica que su método está haciendo demasiado. Si necesita devolver más de un valor, es probable que el método haga más de una cosa. Si los datos están estrechamente relacionados, probablemente se beneficiarían de una clase que contenga ambos valores.

Por supuesto, este no es SIEMPRE el caso, pero he encontrado que generalmente es el caso.

En otras palabras, creo que tiene razón para evitarlos.

0

En general, nunca los uso, creo que son confusos y demasiado fáciles de abusar. De vez en cuando, usamos parámetros de ref, pero eso tiene más que ver con pasar en estructuras que recuperarlas.

0

Tu opinión me parece razonable.

Otro inconveniente de los parámetros de salida es el código adicional necesario para pasar resultados de una función a otra. Debe declarar la (s) variable (s), llamar a la función para obtener sus valores y luego pasar los valores a otra función. No puedes anidar las llamadas a funciones. Esto hace que el código se lea de manera muy imperativa, en lugar de declarativo.

1

Creo que son útiles para obtener los identificadores de filas insertadas recientemente en el mismo comando de SQL, pero no creo que los he usado para mucho más.

0

C++ 0x está obteniendo tuplas, una cosa similar a una estructura anónima, cuyos miembros se accede por índice. Los programadores de C++ podrán empacar múltiples valores en uno de esos y devolverlo. ¿Tiene C# algo así? ¿Puede devolver una matriz, tal vez, en su lugar? Pero sí, los parámetros de salida son un poco incómodos y poco claros.

+0

C# puede devolver una matriz fácilmente. Pero devolver una matriz (que es esencialmente lo que es también la tupla) me parece bastante no semántica, y puede ser confusa. Si siempre devuelve el mismo conjunto de valores, entonces las variables de salida me parecen una mejor opción. –

+3

C# 4.0 introducirá una característica muy innovadora ... la Tuple :) –

+0

¡Me encanta! : P –

20

Ellos tienen su lugar. El método Int32.TryParse es un buen ejemplo de un uso efectivo de un parámetro out.

bool result = Int32.TryParse(value, out number); 
if (result) 
{ 
    Console.WriteLine("Converted '{0}' to {1}.", value, number);   
} 
+1

Buen ejemplo. El TryParse es uno de los únicos métodos que he visto que usa * y * está justificado para hacerlo. – Jagd

+0

Es un caso especial interesante, porque TryParse() existe para evitar la posibilidad de una excepción cuando el valor no contiene un int. – JeffH

+10

Preferiría personalmente "int? Int32.TryParse (valor de cadena)" como la firma, porque entonces puede usar el ?? operador para especificar los valores de retorno. Pero esta función fue escrita antes de que se introdujera Nullables. – Jimmy

1

también veo muy poco uso de los parámetros de salida/ref, aunque en SQL a veces es más fácil pasar un valor de nuevo por un parámetro que por un conjunto de resultados (que a su vez requeriría el uso de un DataReader, etc. .)

Aunque, con un poco de suerte, acabo de crear una función tan rara en C# hoy. Validó una estructura de datos similar a una tabla y devolvió el número de filas y columnas (lo cual fue difícil de calcular porque la tabla podría tener filas/columnas como en HTML). En este caso, el cálculo de ambos valores se realizó al mismo tiempo. Separarlo en dos funciones hubiera resultado en el doble de requisitos de código, memoria y tiempo de CPU. Crear un tipo personalizado solo para que esta función regrese también me parece una exageración.

Entonces, hay momentos en que son lo mejor, pero la mayoría de las veces se puede hacer sin problemas.

1

La cláusula OUTPUT en SQL Server 2005 en adelante es un gran paso adelante para obtener cualquier valor de campo para las filas afectadas por sus declaraciones DML. Creo que hay muchas situaciones en las que esto elimina los parámetros de salida.

En VB6, los parámetros ByRef son buenos para pasar objetos ADO alrededor.

aparte de esos dos casos específicos que me vienen a la mente, tiendo a evitar usarlos.

1

En SQL única ...

parámetros de salida de procedimientos almacenados son útiles.

  1. Supongamos que necesita un valor de nuevo. ¿"Crea #table, insert ... exec, select @var ="? O usa un parámetro de salida?

  2. Para las llamadas de clientes, un parámetro de salida es mucho más rápido que el procesamiento de un conjunto de registros.

  3. El uso de los valores de RETORNO está limitado a un entero con signo.

  4. Más fácil de reutilizar (por ejemplo, un procedimiento de seguridad de verificación ayudante)

  5. Al utilizar los dos: conjuntos de registros = datos, los parámetros de salida = Estado/mensajes/recuento de filas etc

  6. Los procedimientos almacenados de salida de registros puede no tener un tipo fuerte como el UDF o cliente de código

  7. no siempre se puede utilizar una UDF (por ejemplo, el registro de control de seguridad durante más arriba)

Sin embargo, siempre que no use generalmente el mismo parámetro para entrada y salida, hasta que SQL cambie por completo, sus opciones son limitadas. Al decir eso, tengo un caso en el que utilizo un parámetro para los valores de entrada y salida, pero tengo una buena razón.

1

My Two Cents:
Acepto que los parámetros de salida son una práctica preocupante. VBA a menudo es mantenido por personas muy nuevas en la programación y si alguien que mantiene su código no se da cuenta de que un parámetro es ByRef, podrían introducir algunos errores lógicos serios. También tiende a romper el paradigma Propiedad/Función/Sub.
Otra razón que el uso de parámetros de salida es una mala práctica es que si realmente hace necesidad de que volveremos más de un valor, lo más probable es que usted debe tener esos valores en una estructura de datos como una clase o un tipo definido por el usuario.
Sin embargo, pueden resolver algunos problemas.VB5 (y, por lo tanto, VBA para Office 97) no permitió que una función devolviera una matriz. Esto significaba que cualquier cosa que devuelva o altere una matriz tendría que hacerlo a través de un parámetro de "salida". En VB6 se ha agregado esta capacidad, pero VB6 todavía obliga a los parámetros de la matriz a ser por referencia (para evitar una copia excesiva en la memoria). Ahora puede devolver un valor desde una función que altera una matriz. Pero será un poco lento (debido a las acrobacias que ocurren detrás de escena); también puede confundir a los novatos haciéndoles creer que la entrada de la matriz no se verá alterada (lo que solo será cierto si alguien lo estructura específicamente de esa manera). Así que me parece que si tengo una función que altera una matriz, se reduce la confusión de solo usar un sub en lugar de una función (y también será un poco más rápido).
Otro posible escenario sería si mantiene el código y desea agregar un valor de salida sin romper la interfaz. puede agregar un parámetro de salida opcional y estar seguro de que no va a romper ningún código anterior. No es una buena práctica, pero si alguien quiere algo arreglado en este momento y no tiene tiempo para hacerlo de la "manera correcta" y reestructurar todo, esto puede ser una práctica adición a su caja de herramientas.
Sin embargo, si está desarrollando cosas desde cero y necesita devolver valores múltiples, debería considerar:
1. Desbloqueo de la función.
2. Devolución de un UDT.
3. Devolución de una clase.