technical practices handling exceptions example custom best c# design-patterns exception if-statement

practices - throw custom exception c#



Cómo evitar múltiples IFs anidadas (6)

Creo que esto te será útil:
http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism

Actualmente estoy tratando de reestructurar mi programa para que sea más OO y para implementar mejor los patrones conocidos, etc.

Tengo bastantes declaraciones IF anidadas y quiero deshacerme de ellas. ¿Cómo puedo hacer esto? Mi primer enfoque fue hacerlo con excepciones, por ejemplo,

public static Boolean MyMethod(String param) { if (param == null) throw new NullReferenceException("param may not be null"); if (param.Equals("none") || param.Equals("0") || param.Equals("zero")) throw new ArgumentNullException("param may not be zero"); // Do some stuff with param // This is not executed if param is null, as the program stops a soon // as one of the above exceptions is thrown }

El método se utiliza en la clase principal de la aplicación, por ejemplo,

static void Main() { try { Boolean test = MyClass.MyMethod(null); // Will throw an exception } catch (Exception ex) { MessageBox.Show(ex.Message, "Error"); }

Creo que esto es bastante bueno, ya que evita las declaraciones anidadas y casi todas las acciones de los métodos están bien organizadas en un nivel.

Al igual que con las declaraciones IF, el método se vería así.

public Boolean MyMethod(String param) { if (param != null) { if (!param.Equals("none") && !param.Equals("0") && !param.Equals("zero")) { // Do some stuff with param } else { MessageBox.Show("param may not be zero", "Error"); } else { MessageBox.Show("param may not be null", "Error"); } }

Lo cual me parece muy, muy feo y difícil de mantener.

Ahora, la pregunta es; ¿Es este enfoque bueno ? Lo sé, eso podría ser subjetivo, pero ¿cómo superar los IF anidados (1 o 2 niveles no son tan malos, pero empeoran después de eso ...)


Es realmente una pregunta bastante amplia para responder, ya que realmente dependería de la funcionalidad de las sentencias if.

Ciertamente, cuando es posible, trato de reemplazar las declaraciones if anidadas con un conmutador, pero esto no siempre es posible.

La verificación de la validez de los parámetros es un buen enfoque, pero observe cómo se encuentra más arriba en el código, es decir, tiene las declaraciones de lanzamiento, pero no la captura en la clase que lo lanza.


Quizás AspectF pueda ayudarte en este caso:

public Boolean MyMethod(String param) { try { AspectF.Define .ErrorMsgIfNull(param, "must be not null") .ErrorMsgIfEquals(new string[] {"None", "Zero", "0"}, "may not be zero") //... // use your own "AspectFlets" you wrote //... .Do(() => { // Do some stuff with param // This is not executed if param is null, as the program stops a soon // as one of the above exceptions is thrown }); }

Si tiene varias condiciones que cumplir (o evitar) que podrían hacer un bloque feo de anidados si, de esta manera, factorizar el código puede ayudarlo a hacer las cosas un poco más descriptivas.

Los métodos en el código anterior son solo ejemplos que no existen, pero que se pueden implementar fácilmente.


Realmente depende de su propósito. En su primera muestra, las declaraciones if tienen el propósito de hacer cumplir un contrato, asegurándose de que la entrada al método cumpla con ciertos requisitos. En esos casos, mi propio código tiende a parecerse mucho a su código.

En el caso de usar los bloques if para controlar el flujo de un método (en lugar de hacer cumplir un contrato), a veces puede ser un poco más difícil. A veces me encuentro con un código como el siguiente ejemplo (extremadamente simplificado):

private void SomeMethod() { if (someCondition == true) { DoSomething(); if (somethingElse == true) { DoSomethingMore(); } } else { DoSomethingElse(); } }

En este caso, parece que el método tiene varias responsabilidades, por lo que en este caso probablemente elegiría dividirlo en varios métodos:

private void SomeMethod() { if (someCondition == true) { DoItThisWay(); } else { DoSomethingElse(); } } private void DoItThisWay() { DoSomething(); if (somethingElse == true) { DoSomethingMore(); } }

Esto hace que cada método sea mucho más simple con menos código anidado, y también puede aumentar la legibilidad, si los métodos reciben buenos nombres.


Su problema es conocido como el anti-patrón de punta de flecha.

Hay enfoques pragmáticos, como las declaraciones de Guard que ha mostrado en su muestra, a patrones de diseño completos, evitando si (y si no) todos juntos ...

Muchos recursos sobre cómo resolverlos:

http://www.codinghorror.com/blog/2006/01/flattening-arrow-code.html

http://www.lostechies.com/blogs/chrismissal/archive/2009/05/27/anti-patterns-and-worst-practices-the-arrowhead-anti-pattern.aspx

http://elegantcode.com/2009/08/14/observations-on-the-if-statement/