2008-08-11 10 views
6

Imagine que un objeto con el que está trabajando tiene una colección de otros objetos asociados, por ejemplo, la colección Controls en un WinForm. Desea comprobar si hay un determinado objeto en la colección, pero la colección no tiene un método Contains(). Hay varias maneras de lidiar con esto.Uso de excepciones no controladas en lugar de Contiene()?

  • implementar su propio método Contains() por bucle a través de todos los elementos de la colección para ver si uno de ellos es lo que busca. Este parece ser el enfoque de "mejores prácticas".
  • Recientemente me encontré con algo de código en lugar de un bucle, hubo un intento de acceder al objeto dentro de una instrucción try, de la siguiente manera:
try 
{ 
    Object aObject = myCollection[myObject]; 
} 
catch(Exception e) 
{ 
    //if this is thrown, then the object doesn't exist in the collection 
} 

Mi pregunta es cómo los pobres de una práctica de programación ¿considera que la segunda opción es y por qué? ¿Cómo se compara el rendimiento del mismo con un ciclo de la colección?

Respuesta

2

Tendría que decir que esta es una práctica bastante mala. Si bien algunas personas pueden contentarse en decir que recorrer la colección es menos eficiente que arrojar una excepción, hay una sobrecarga para lanzar una excepción. También me pregunto por qué está utilizando una colección para acceder a un elemento por clave cuando sería más adecuado usar un diccionario o hashtable.

Mi principal problema con este código sin embargo, es que, independientemente del tipo de excepción lanzada, que siempre va a quedar con el mismo resultado.

Por ejemplo, podría lanzarse una excepción porque el objeto no existe en la colección, o porque la colección en sí es nula o porque no puede convertir myCollect [myObject] en un objeto.

Todas estas excepciones se manejarán de la misma manera, lo que puede no ser su intención.

Estos son un par de artículos agradables de cuando y donde se considera Normalamente aceptable para lanzar excepciones:

me gusta especialmente esta cita del segundo artículo :

es importante que las excepciones de una re lanzado sólo cuando se produce una actividad no válida inesperado o que impide un método de completar su función normal . El manejo de excepciones introduce una pequeña sobrecarga y reduce rendimiento por lo que no debe ser utilizado para flujo del programa normal en lugar de procesamiento condicional. También puede ser difícil de mantener el código que utiliza incorrectamente el manejo de excepciones en esta forma .

0

Si, mientras escribe su código, espera que este objeto esté en la colección, y luego durante el tiempo de ejecución encuentra que no lo es, lo llamaría un caso excepcional, y es apropiado usar una excepción.

Sin embargo, si simplemente está probando la existencia de un objeto, y encuentra que no está allí, esto no es excepcional. Usar una excepción en este caso no es apropiado.

El análisis del rendimiento del tiempo de ejecución depende de la colección real utilizada y del método si la está buscando. Eso no debería importar sin embargo. No permita que la ilusión de optimización lo engañe para escribir un código confuso.

-2

Este último es una solución aceptable. Aunque definitivamente captaría la excepción específica (ElementNotFound?) Que arroja la colección en ese caso.

Speedwise, depende del caso común. Si es más probable que encuentre el elemento que no, la solución de excepción será más rápida. Si es más probable que falle, dependerá del tamaño de la colección y su velocidad de iteración. De cualquier forma, querrás medir el uso normal para ver si esto es realmente un cuello de botella antes de preocuparte por una velocidad como esta. Primero busque claridad, y la última solución es mucho más clara que la primera.

0

tendría que pensar en ello más en cuanto a cuánto me gusta ... mi instinto es, eh, no tanto ...

EDIT: los comentarios de Ryan Fox en el caso excepcional es perfecto , Estoy de acuerdo

En cuanto al rendimiento, depende del indexador de la colección. C# le permite anular el operador del indexador, por lo que si está haciendo un bucle for como el método contains que escribiría, entonces será tan lento (con unos pocos nanosegundos más lento debido al try/catch ... pero nada a preocuparse a menos que ese código esté dentro de un gran bucle).

Si el indexador es O (1) (o incluso O (log (n)) ... o algo más rápido que O (n)), entonces la solución try/catch sería más rápida, por supuesto.

Además, supongo que el indexador está lanzando la excepción, si está devolviendo nulo, podría simplemente verificar la nulidad y no usar el try/catch.

0

En general, el manejo de excepciones para el flujo de programa y la lógica es una mala práctica. Personalmente, creo que la última opción es el uso inaceptable de excepciones. Dadas las características de los lenguajes comúnmente utilizados en la actualidad (como Linq y lambdas en C# por ejemplo), no hay razón para no escribir su propio método Contiene().

Como reflexión final, estos días la mayoría de las colecciones hacen tienen un método ya contiene. Así que creo que en su mayor parte esto no es un problema.

4

La regla general es evitar el uso de excepciones para el flujo de control a menos que las circunstancias que desencadenarán la excepción sean "excepcionales", por ejemplo, extremadamente raras.

Si esto es algo que va a pasar con normalidad y regularidad que definitivamente no debe ser manejado como una excepción.

Las excepciones son muy, muy lento debido a toda la sobrecarga que implica, por lo que no pueden ser motivos de rendimiento, así, si está ocurriendo con la suficiente frecuencia.

1

Las excepciones deben ser excepcionales.

Algo así como 'La colección está ausente debido a que la base de datos ha caído por debajo de él' es excepcional

Algo así como 'la clave no está presente' es un comportamiento normal para un diccionario.

Para su ejemplo específico de una colección Control de winforms, la propiedad Controls tiene un método ContainsKey, que es lo que se supone que debe usar.

No hay ContainsValue porque cuando se trata de diccionarios/hashtables, no hay una manera rápida de iterar a través de toda la colección, de verificar si hay algo presente, por lo que se desalienta de hacerlo.

cuanto a por qué excepciones deben ser excepcionales, se trata de 2 cosas

  1. indicando lo que su código está tratando de hacer. Desea que su código coincida con lo que intenta lograr, lo más cerca posible, para que sea legible y fácil de mantener. El manejo de excepciones agrega un montón de cruces adicionales que se interponen en el camino de este propósito

  2. Brevedad de código. Desea que su código haga lo que está haciendo de la manera más directa, por lo que es legible y mantenible. Una vez más, el crumble agregado por el manejo de excepciones se interpone en el camino de esto.

0

Echa un vistazo a esta entrada del blog de Krzysztof: http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

Las excepciones deben ser utilizados para comunicar las condiciones de error, pero no deben ser utilizados como lógica de control (especialmente cuando hay formas mucho más simples a determinar una condición, como Contiene).

Parte del problema es que las excepciones, mientras que no es caro para tiro son caros de captura y todas las excepciones se encuentran atrapados en algún momento.

Cuestiones relacionadas