Veo el siguiente patrón de código por todas partes en la base de código de mi empresa (aplicación .NET 3.5):
bool Foo(int barID, out Baz bazObject) {
try {
// do stuff
bazObject = someResponseObject;
return true;
}
catch (Exception ex) {
// log error
return false;
}
}
// calling code
BazObject baz = new BazObject();
fooObject.Foo(barID, out baz);
if (baz != null) {
// do stuff with baz
}
Estoy tratando de entender por qué haría esto en lugar de que el Foo
método simplemente tome la ID y devuelva un Baz
objeto, en lugar de devolver un valor que no se utiliza y que el objeto real sea un parámetro de referencia o salida.
¿Hay algún beneficio oculto de este estilo de codificación que me falta?
c#
code-quality
coding-style
Wayne Molina
fuente
fuente
baz
sernull
y elbool
ser devuelto nofalse
son equivalentes. nunca es así, a menos que se actualice antes de que se lance , cuando se devuelva nunca lo será . Sería de gran ayuda enormemente si la especificación de estaban disponibles. De hecho, este es quizás el problema más grave exhibido por este código.new BazObject()
null
bazObject
Exception
Foo
false
baz
null
Foo
Respuestas:
Usualmente usas ese patrón para poder escribir código como este:
se usa en CLR para TryGetValue en la clase de diccionario, por ejemplo. Evita cierta redundancia, pero los parámetros de salida y referencia siempre me parecieron un poco desordenados.
fuente
Este es el antiguo código de estilo C, antes de que hubiera excepciones. El valor de retorno indicó si el método fue exitoso o no, y si lo fuera, el parámetro se llenaría con el resultado.
En .net tenemos excepciones para ese propósito. No debería haber ninguna razón para seguir este patrón.
[editar] Obviamente, hay implicaciones de rendimiento en el manejo de excepciones. Tal vez eso tenga algo que ver con eso. Sin embargo, en ese fragmento de código ya se está lanzando una excepción. Sería más limpio dejarlo subir por la pila hasta que quede atrapado en un lugar más apropiado.
fuente
if (baz.Select())
pero la mayoría de las veces el valor de retorno simplemente se descarta y el valor se compara con nulo o alguna propiedad.Dado el fragmento de código, parece completamente inútil. Para mí, el patrón de código inicial sugeriría que nulo para BazObject sería un caso aceptable y el retorno de bool es una medida para determinar un caso de falla de forma segura. Si el siguiente código era:
Esto tendría más sentido para mí hacerlo de esta manera. Quizás este es un método que alguien antes usaba para garantizar que se pasara baz por referencia sin comprender cómo funcionan realmente los parámetros de objeto en C #.
fuente
A veces, este patrón es útil cuando a usted, la persona que llama, no le importa si el tipo devuelto es una referencia o un tipo de valor. Si está llamando a dicho método para recuperar un tipo de valor, ese tipo de valor necesitará un valor no válido establecido (por ejemplo, double.NaN) o necesitará alguna otra forma de determinar el éxito.
fuente
La idea es devolver un valor que indique si el proceso fue exitoso, permitiendo un código como este:
Si el objeto no puede ser nulo (lo que parece correcto en su ejemplo), es mejor hacerlo de la siguiente manera:
Si el objeto puede ser nulo, las excepciones son el camino a seguir:
Es un patrón común utilizado en C, donde no hay excepciones. Permite que la función devuelva una condición de error. Las excepciones son generalmente una solución mucho más limpia.
fuente