Pregunta

Imagina un objeto en el que está trabajando tiene una colección de otros objetos relacionados con ella, por ejemplo, la colección de Controles en un WinForm.Desea comprobar si un determinado objeto en la colección, pero la colección no tiene un Contains() método.Hay varias maneras de lidiar con esto.

  • Implementar su propio Contains() método por el bucle a través de todos los elementos de la colección, a ver si uno de ellos es lo que usted está buscando.Esta parece ser una de las "mejores prácticas".
  • Recientemente encontré un código donde en lugar de un bucle, hubo un intento de acceso 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 ¿se considera la segunda opción y por qué?¿Cómo es el rendimiento de la misma en comparación con un bucle a través de la colección?

¿Fue útil?

Solución

Yo tendría que decir que esta es bastante mala práctica.Mientras algunas personas puede ser feliz de decir que el bucle a través de la colección es menos eficiente para lanzar una excepción, hay una sobrecarga a lanzar una excepción.También me pregunta por qué se está utilizando una colección para tener acceso a un elemento clave cuando sería más adecuado para el uso de un diccionario o hashtable.

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

Por ejemplo, una excepción podría ser arrojados porque el objeto no existe en la colección, o debido a que la colección en sí es null o porque no pueden lanzar myCollect[myObject] para aObject.

Todas estas excepciones son manejados de la misma manera, que puede no ser su intención.

Estos son un par de buenos artículos sobre cuando y donde se usally considera aceptable para lanzar excepciones:

Particularmente me gusta esta cita de la artículo segundo:

Es importante que las excepciones son lanzado sólo cuando un inesperado o la actividad no válida ocurre que impide un método de completar su normal la función.Manejo de excepciones introduce una pequeña sobrecarga y baja rendimiento, por lo que no debe ser utilizado para normal el flujo de un programa en lugar de el procesamiento condicional.También puede ser difícil mantener el código que abusa de manejo de excepciones en este manera.

Otros consejos

La regla general es evitar el uso de excepciones para el control de flujo a menos que las circunstancias en la que se activará la excepción son "excepcionales" - por ejemplo, muy raro!

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

Las excepciones son muy, muy, muy lento debido a la sobrecarga que implica, por lo tanto, pueden ser motivos de rendimiento, si es que sucede bastante a menudo.

Si, al escribir el código, se espera que este objeto en la colección y, a continuación, durante el tiempo de ejecución que no, que yo definiría como un caso excepcional, y es adecuado para usar una excepción.

Sin embargo, si usted está simplemente en las pruebas de la existencia de un objeto, y usted encontrará que no es, no, esto no es excepcional.El uso de una excepción en este caso no es la correcta.

El análisis del rendimiento en tiempo de ejecución depende de la propia recopilación de ser utilizado, y el método de búsqueda.Que no importa aunque.No dejes que la ilusión de la optimización de engañar a la escritura confusa código.

Yo tendría que pensar más en cuanto a lo mucho que me gusta...mi instinto es, eh, no tanto...

EDITAR:Ryan Fox comentarios sobre el caso excepcional es perfecto, estoy de acuerdo

Como para el rendimiento, depende del indizador en la colección.C# permite reemplazar el indizador de operador, de manera que si se está haciendo un bucle for como la que contiene el método de escritura, entonces no será tan lento (tal vez unos pocos nanosegundos más lento debido al try/catch...pero nada de que preocuparse a menos que el propio código está dentro de un enorme bucle).

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

También, estoy suponiendo que el indizador es lanzar la excepción, si es que se devuelva null, usted podría, por supuesto, acabo de comprobar el valor null y no usar el try/catch.

En general, el uso de excepciones para el flujo del programa y la lógica es una mala práctica.Personalmente, creo que la última opción es inaceptable el uso de excepciones.Teniendo en cuenta las características de los idiomas comúnmente utilizados en estos días (como Linq y funciones lambda en C# por ejemplo) que no hay motivo para escribir su propio método Contains ().

Como pensamiento final, en estos días la mayoría de las colecciones ¿ tener un método contains ya.Así que creo que para la mayor parte, esto es un no-problema.

Las excepciones deben ser excepcionales.

Algo así como "La colección está perdiendo debido a la base de datos se ha caído de la parte de debajo de ti' es excepcional

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

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

No hay ContainsValue porque cuando se trata de diccionarios/tablas de hash, que no hay manera rápida de corto de la iteración a través de toda la colección, de la comprobación de si algo está presente, por lo que es realmente disuadidos de hacerlo.

En cuanto a por QUÉ las Excepciones deben ser excepcionales, se trata de 2 cosas

  1. Indica lo que su código está tratando de hacer.Usted quiere tener su código coincida con lo que se está tratando de lograr, de la mejor manera posible, por lo que es legible y mantenible.Manejo de excepciones añade un montón de resto adicional que se interpone en el camino de este propósito

  2. La brevedad de código.Usted quiere que su código para hacer lo que está haciendo en la forma más directa, por lo que es legible y mantenible.De nuevo, el resto añadido por el manejo de excepciones se interpone en el camino de este.

Echa un vistazo a este post del blog de Krzystof: http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

Las excepciones deben ser utilizados para la comunicación de las condiciones de error, pero que no debe ser utilizado como la lógica de control (especialmente cuando hay muchas maneras más simples para determinar una condición, tal como se Contiene).

Parte del problema es que las excepciones, aunque no es caro tiro son caros captura y todas las excepciones están atrapados en algún momento.

El último es una solución aceptable.Aunque definitivamente, me gustaría coger a la excepción específica (ElementNotFound?) que la colección de lanza en ese caso.

Speedwise, depende el caso común.Si usted es más probable encontrar el elemento que no, la excepción de la solución será más rápido.Si usted es más propenso a fallar, entonces depende del tamaño de la colección y su iteración de la velocidad.De cualquier manera, te gustaría medida contra el uso normal para ver si esto es de hecho un cuello de botella antes de preocuparse de la velocidad como este.Ir por la claridad de primera, y la segunda solución es mucho más clara que la anterior.

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