Pregunta

Permítanme comenzar diciendo que no defiendo este enfoque, pero lo vi recientemente y me preguntaba si habría un nombre que pudiera usar para señalar al culpable.Así que ahí va.

Ahora tienes un método y quieres devolver un valor.Tú también Quiero devolver un código de error.Por supuesto, las excepciones son una opción mucho mejor, pero por alguna razón desea un código de error.Recuerde, estoy jugando al abogado del diablo aquí.Entonces creas una clase genérica, como esta:

class FunctionResult<T>
{
    public T payload;
    public int result;
}

Y luego declara tus funciones así:

FunctionResult<string> MyFunction()
{
    FunctionResult<string> result;
    //...

    return result;
}

Una variación de este patrón es utilizar una enumeración para el código de error en lugar de una cadena.Ahora, volvamos a mi pregunta:¿Existe un nombre para esto y, de ser así, cuál es?

¿Fue útil?

Solución

Estoy de acuerdo en que esto no es específicamente un antipatrón.Puede ser un olor dependiendo del uso.Hay razones por las que uno realmente no querría utilizar excepciones (p. ej.los errores que se devuelven no son "excepcionales", para empezar).

Hay casos en los que desea que un servicio devuelva un modelo común para sus resultados, incluidos errores y buenos valores.Esto podría estar envuelto por una interacción de servicio de bajo nivel que traduce el resultado en una excepción u otra estructura de error, pero a nivel del servicio, permite que el servicio devuelva un resultado y un código de estado sin tener que definir alguna estructura de excepción que pueda tienen que ser trasladados a través de una frontera remota.

Es posible que este código tampoco sea necesariamente un error:Considere una respuesta HTTP, que consta de muchos datos diferentes, incluido un código de estado, junto con el cuerpo de la respuesta.

Otros consejos

Bueno es no un antipatrón.La biblioteca estándar de C++ hace uso de esta característica y .NET incluso ofrece una versión especial. FunctionResult clase en el marco .NET.Se llama Nullable.Sí, esto no se limita a los resultados de funciones, pero se puede utilizar en tales casos y, de hecho, es muy útil aquí.Si .NET 1.0 ya hubiera tenido la Nullable clase, ciertamente habría sido utilizado para la NumberType.TryParse métodos, en lugar de out parámetro.

Normalmente paso la carga útil como referencia (no constante) y el código de error como valor de retorno.

Soy desarrollador de juegos, desterramos las excepciones.

Konrad tiene razón, C# usa valores de retorno duales todo el tiempo.Pero me gusta TryParse, Dictionary.TryGetValue, etc.métodos en C#.

int value;
if (int.TryParse("123", out value)) {
    // use value
}

en lugar de

int? value = int.TryParse("123");
if (value != null) {
    // use value
}

...principalmente porque el patrón Nullable no se escala a tipos de retorno que no son de valor (es decir, instancias de clase).Esto no funcionaría con Dictionary.TryGetValue().Y TryGetValue es mejor que KeyNotFoundException (no hay "excepciones de primera oportunidad" constantemente en el depurador, posiblemente más eficiente), mejor que la práctica de Java de get() que devuelve nulo (¿qué pasa si se esperan valores nulos) y más eficiente que tener que hacerlo? llame a ContieneKey() primero.

Pero esto es todavía un poco complicado: dado que parece C#, entonces debería usar un parámetro de salida.Todas las ganancias de eficiencia probablemente se pierdan al crear una instancia de la clase.

(Podría ser Java excepto que el tipo "cadena" está en minúsculas.En Java, por supuesto, debes usar una clase para emular valores de retorno duales).

No estoy seguro de que esto sea un antipatrón.Comúnmente he visto esto usado en lugar de excepciones por razones de rendimiento, o quizás para hacer más explícito el hecho de que el método puede fallar.Para mí, parece ser una preferencia personal más que un antipatrón.

Estoy de acuerdo con quienes dicen que esto no es un antipatrón.Es un patrón perfectamente válido en ciertos contextos.Las excepciones son para excepcional situaciones, los valores de retorno (como en su ejemplo) deben usarse en situaciones esperadas.Algunos dominios esperan resultados válidos e inválidos de las clases, y ninguno de ellos debe modelarse como excepción.

Por ejemplo, dada X cantidad de gasolina, ¿puede un automóvil ir de A a B y, de ser así, cuánta gasolina queda?Ese tipo de pregunta es ideal para la estructura de datos que proporcionó.Se espera no poder realizar el viaje de A a B, por lo que no se debe utilizar una excepción.

En realidad, este enfoque es mucho mejor que otros que he visto.Algunas funciones en C, por ejemplo, cuando encuentran un error regresan y parecen tener éxito.La única forma de saber que fallaron es llamar a una función que obtendrá el último error.

¡Pasé horas intentando depurar el código de semáforo en mi MacBook antes de que finalmente descubriera que sem_init no funciona en OSX!Se compiló sin errores y se ejecutó sin causar ningún error; sin embargo, el semáforo no funcionó y no pude entender por qué.Me da lástima la gente que porta una aplicación que utiliza Semáforos POSIX a OSX y debe abordar problemas de contención de recursos que ya se han depurado.

¿Qué tal el patrón "No puedo decidir si se trata de un error o no"?Parece que si realmente tuviera una excepción pero quisiera devolver un resultado parcial, incluiría el resultado en la excepción.

Si no desea utilizar excepciones, la forma más limpia de hacerlo es hacer que la función devuelva el código de error/éxito y tome una referencia o un argumento de puntero que se complete con el resultado.

Yo no lo llamaría un antipatrón.Es un método viable muy bien probado que a menudo es preferible al uso de excepciones.

Si espera que su método falle ocasionalmente, pero no lo considera excepcional, prefiero este patrón tal como se usa en .NET Framework:

bool TryMyFunction(out FunctionResult result){    

     //...    
     result = new FunctionResult();
}

Los debates sobre olores y antipatrones me recuerdan a los programas de televisión "Survivor", donde tienes varias construcciones de programación que intentan expulsar a otros de la isla.Preferiría ver "la construcción X tiene tales y tales pros y contras", en lugar de una lista en continua evolución de edictos sobre lo que se debe y no se debe hacer.

En defensa de la designación antipatrón, este código se presta para ser utilizado de varias maneras:

  1. Objeto x = MiFunción().payload; (ignorando el resultado devuelto - muy malo)
  2. código int = MiFunción().resultado; (desechar la carga útil; puede estar bien si ese es el uso previsto).
  3. ResultadoFunción x = MiFunción();//... (un montón de objetos FunctionResult adicionales y código adicional para verificarlos por todos lados)

Si necesita utilizar códigos de retorno, está bien.Pero luego use códigos de retorno.No intentes llevar una carga útil adicional con él.eso es lo que árbitro y afuera Los parámetros (C#) son para.Los tipos que aceptan valores NULL pueden ser una excepción, pero solo porque hay azúcar adicional en el lenguaje para respaldarlos.

Si aún no está de acuerdo con esta evaluación, VOTO ABAJO esta respuesta (no toda la pregunta).Si crees que es un antipatrón, VOTALO.Usaremos esta respuesta para ver qué piensa la comunidad.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top