Encontré esta página de MSDN que dice:
No arrojes Exception , SystemException , NullReferenceException o IndexOutOfRangeException intencionalmente desde tu propio código fuente.
Desafortunadamente, no se molesta en explicar por qué. Puedo adivinar las razones, pero espero que alguien más autorizado en el tema pueda ofrecer su visión.
Los dos primeros tienen un sentido obvio, pero los dos últimos parecen ser los que le gustaría emplear (y de hecho, lo tengo).
Además, ¿son estas las únicas excepciones que se deben evitar? Si hay otros, ¿cuáles son y por qué deberían evitarse también?
c#
exception-handling
DonBoitnott
fuente
fuente
NullArgumentException
que algunas personas pueden confundir a ambos.ApplicationException
Respuestas:
Exception
es el tipo base para todas las excepciones y, como tal, es terriblemente inespecífico. Nunca debería lanzar esta excepción porque simplemente no contiene ninguna información útil. Llamar a la captura de código para las excepciones no pudo eliminar la ambigüedad de la excepción lanzada intencionalmente (de su lógica) de otras excepciones del sistema que son completamente indeseables y señalan fallas reales.La misma razón también se aplica a
SystemException
. Si observa la lista de tipos derivados, puede ver una gran cantidad de otras excepciones con semánticas muy diferentes.NullReferenceException
yIndexOutOfRangeException
son de un tipo diferente. Ahora bien, estas son excepciones muy específicas, por lo que lanzarlas podría estar bien. Sin embargo, todavía no querrás lanzarlos, ya que generalmente significan que hay algunos errores reales en tu lógica. Por ejemplo, la excepción de referencia nula significa que está intentando acceder a un miembro de un objeto que esnull
. Si esa es una posibilidad en su código, entonces siempre debe buscar explícitamentenull
y lanzar una excepción más útil en su lugar (por ejemploArgumentNullException
). De manera similar,IndexOutOfRangeException
los correos electrónicos ocurren cuando accede a un índice no válido (en matrices, no en listas). Siempre debe asegurarse de no hacer eso en primer lugar y verificar primero los límites de, por ejemplo, una matriz.Hay algunas otras excepciones como esas dos, por ejemplo
InvalidCastException
oDivideByZeroException
, que se lanzan por fallas específicas en su código y generalmente significan que está haciendo algo mal o que no está verificando primero algunos valores no válidos. Al arrojarlos a sabiendas de su código, solo está dificultando que el código de llamada determine si se lanzaron debido a alguna falla en el código, o simplemente porque decidió reutilizarlos para algo en su implementación.Por supuesto, hay algunas excepciones (ja) a estas reglas. Si está creando algo que puede causar una excepción que coincida exactamente con una existente, no dude en usarlo, especialmente si está tratando de igualar algún comportamiento incorporado. Solo asegúrese de elegir un tipo de excepción muy específico.
Sin embargo, en general, a menos que encuentre una excepción (específica) que satisfaga sus necesidades, siempre debe considerar la posibilidad de crear sus propios tipos de excepción para excepciones esperadas específicas. Especialmente cuando está escribiendo código de biblioteca, esto puede ser muy útil para separar las fuentes de excepción.
fuente
IList
implementación, no está en su poder afectar los índices solicitados, es un error lógico de la persona que llama cuando un índice no es válido, y solo puede informarles de este error lógico lanzando una excepción apropiada. ¿Por quéIndexOutOfRangeException
no es apropiado?IList
, lanzará unArgumentOutOfRangeException
como sugiere la documentación de la interfaz .IndexOutOfRangeException
es para matrices y, hasta donde yo sé, no se pueden volver a implementar matrices.NullReferenceException
generalmente se lanza internamente como un caso especial de unAccessViolationException
(IIRC, la prueba es algo asícmp [addr], addr
, es decir, intenta desreferenciar el puntero y si falla con una violación de acceso, maneja la diferencia entre NRE y AVE en el manejador de interrupciones resultante). Entonces, aparte de las razones semánticas, también hay algunas trampas involucradas. También podría ayudarlo a desanimarlo de verificarnull
manualmente cuando no sea útil; si de todos modos va a lanzar una NRE, ¿por qué no dejar que .NET lo haga?Sospecho que la intención con los últimos 2 es evitar la confusión con las excepciones incorporadas que tienen un significado esperado. Sin embargo, soy de la opinión de que si está preservando la intención exacta de la excepción : es la correcta para
throw
. Por ejemplo, si está escribiendo una colección personalizada, parece completamente razonable usarloIndexOutOfRangeException
: más claro y más específico, en mi opinión, queArgumentOutOfRangeException
. Y aunqueList<T>
podría elegir lo último, hay al menos 41 lugares (cortesía del reflector) en el BCL (sin incluir los arreglos) que se lanzan a medidaIndexOutOfRangeException
, ninguno de los cuales es de "nivel bajo" lo suficientemente como para merecer una exención especial. Así que sí, creo que se puede argumentar con justicia que esa directriz es una tontería. Igualmente,NullReferenceException
es un poco útil en métodos de extensión, si desea preservar la semántica que:lanza un
NullReferenceException
cuandoobj
esnull
.fuente
SomeMethod()
no necesita realizar el acceso de miembros, es incorrecto forzarlo. Del mismo modo: tome ese punto con los 41 lugares en el BCL que crean personalizadoIndexOutOfRangeException
y los 16 lugares que crean personalizadoNullReferenceException
ArgumentNullException
lugar de unNullReferenceException
. Incluso si el azúcar sintáctico de los métodos de extensión permite la misma sintaxis que el acceso a miembros normales, todavía funciona de manera muy diferente. Y obtener una NRE deMyStaticHelpers.SomeMethod(obj)
sería simplemente incorrecto.Como señala, en el artículo Creando y lanzando excepciones (Guía de programación de C #) bajo el tema Cosas que evitar al lanzar excepciones , Microsoft de hecho enumera
System.IndexOutOfRangeException
como un tipo de excepción que no debe lanzarse intencionalmente desde su propio código fuente.En contraste, sin embargo, en el artículo throw (Referencia de C #) , Microsoft parece violar sus propias pautas. Aquí hay un método que Microsoft incluyó en su ejemplo:
Por lo tanto, Microsoft en sí no está siendo consistente, ya que demuestra el lanzamiento de
IndexOutOfRangeException
su documentación parathrow
!Esto me lleva a pensar que, al menos para el caso de
IndexOutOfRangeException
, puede haber ocasiones en las que el tipo de excepción puede ser lanzado por el programador y se considera una práctica aceptable.fuente
Cuando leí su pregunta, me pregunté en qué condiciones uno querría lanzar los tipos de excepción
NullReferenceException
,InvalidCastException
oArgumentOutOfRangeException
.En mi opinión, cuando me encuentro con uno de esos tipos de excepciones, yo (el desarrollador) me preocupa la advertencia en el sentido de que el compilador me está hablando. Entonces, permitirle a usted (el desarrollador) lanzar tales tipos de excepción es equivalente a (el compilador) vender la responsabilidad. Por ejemplo, esto sugiere que el compilador ahora debería permitir al desarrollador decidir si un objeto es
null
. Pero hacer tal determinación debería ser realmente el trabajo del compilador.PD: Desde 2003 he estado desarrollando mis propias excepciones para poder lanzarlas como desee. Creo que se considera una buena práctica hacerlo.
fuente
Dejando la discusión sobre
NullReferenceException
y aIndexOutOfBoundsException
un lado:¿Qué hay de atrapar y lanzar
System.Exception
? He lanzado mucho este tipo de excepción en mi código y nunca me ha fastidiado. De manera similar, muy a menudo capto elException
tipo inespecífico , y también funcionó bastante bien para mí. Entonces, ¿por qué es eso?Por lo general, los usuarios argumentan que deberían poder distinguir las causas de los errores. Desde mi experiencia, hay muy pocas situaciones en las que le gustaría manejar diferentes tipos de excepciones de manera diferente. Para esos casos, en los que espera que los usuarios manejen los errores mediante programación, debe lanzar un tipo de excepción más específico. Para otros casos, no me convence la guía general de mejores prácticas.
Entonces, con respecto al lanzamiento
Exception
, no veo una razón para prohibir esto en todos los casos.EDITAR: también desde la página de MSDN:
Exagerar las cláusulas catch con lógica individual para diferentes tipos de excepciones tampoco es una buena práctica.
fuente