try practices practice handling exceptions ejemplo custom catch best c# exception-handling

practices - throw exception c#



¿Por qué no debemos arrojar estas excepciones? (4)

Me encontré con esta página de MSDN que dice:

No SystemException Exception , SystemException , NullReferenceException ni IndexOutOfRangeException intencionalmente desde su propio código fuente.

Lamentablemente, no se molesta en explicar por qué. Puedo adivinar las razones, pero espero que alguien más autorizado sobre el tema pueda ofrecer su visión.

Los dos primeros tienen algún sentido obvio, pero los dos últimos parecen ser los que te gustaría emplear (y de hecho, tengo).

Además, ¿son estas las únicas excepciones que se deben evitar? Si hay otros, ¿qué son y por qué también deberían evitarse?


Como señala, en el artículo Creación y lanzamiento de excepciones (Guía de programación de C #) bajo el tema Cosas que hay que evitar al lanzar excepciones , Microsoft enumera System.IndexOutOfRangeException como un tipo de excepción que no debe arrojarse intencionalmente desde su propio código fuente.

En contraste, sin embargo, en el lanzamiento del artículo (Referencia de C #) , Microsoft parece violar sus propias pautas. Este es un método que Microsoft incluyó en su ejemplo:

static int GetNumber(int index) { int[] nums = { 300, 600, 900 }; if (index > nums.Length) { throw new IndexOutOfRangeException(); } return nums[index]; }

Por lo tanto, Microsoft no está siendo coherente, ya que demuestra el lanzamiento de IndexOutOfRangeException en su documentación para throw !

Esto me lleva a creer que, al menos en el caso de IndexOutOfRangeException , puede haber ocasiones en que el programador pueda lanzar ese tipo de excepción y se lo considere una práctica aceptable.


Cuando leí tu pregunta, me pregunté en qué condiciones me gustaría arrojar los tipos de excepción NullReferenceException , InvalidCastException o ArgumentOutOfRangeException .

En mi opinión, cuando me encuentro con uno de esos tipos de excepciones, yo (el desarrollador) me siento preocupado por la advertencia en el sentido de que el compilador me está hablando. Entonces, permitirle a usted (el desarrollador) arrojar tales tipos de excepción es equivalente a (el compilador) vendiendo la responsabilidad. Por ejemplo, esto sugiere que el compilador ahora debería permitir al desarrollador decidir si un objeto es null . Pero hacer esa determinación realmente debería ser el trabajo del compilador.

PD: Desde 2003 he estado desarrollando mis propias excepciones para poder lanzarlas como me plazca. Creo que se considera una buena práctica hacerlo.


Sospecho que la intención de 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 usar IndexOutOfRangeException , más clara y más específica, IMO, que ArgumentOutOfRangeException . Y aunque List<T> podría elegir lo último, hay al menos 41 lugares (cortesía de reflector) en el BCL (sin incluir arrays) que arrojan IndexOutOfRangeException medida, ninguno de los cuales es de "bajo nivel" lo suficiente como para merecer una exención especial. Así que sí, creo que puedes argumentar con justicia que esa pauta es tonta. Del mismo modo, NullReferenceException es útil en los métodos de extensión, si desea conservar la semántica que:

obj.SomeMethod(); // this is actually an extension method

arroja una NullReferenceException cuando obj es null .


Exception es el tipo base para todas las excepciones, y como tal terriblemente inespecífico. Nunca deberías lanzar esta excepción porque simplemente no contiene información útil. La captura del código de llamada 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 indeseadas y señalar 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ántica muy diferente.

NullReferenceException y IndexOutOfRangeException son de un tipo diferente. Ahora bien, estas son excepciones muy específicas, por lo que arrojarlas podría estar bien. Sin embargo, todavía no querrás lanzar estos, 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 es null . Si esa es una posibilidad en su código, siempre debe verificar explícitamente null y lanzar una excepción más útil en su lugar (por ejemplo, ArgumentNullException ). Del mismo modo, IndexOutOfRangeException produce 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 los límites de, por ejemplo, una matriz primero.

Hay algunas otras excepciones como esas dos, por ejemplo, InvalidCastException o DivideByZeroException , que se lanzan en busca de fallas específicas en su código y generalmente significan que está haciendo algo mal o que no está buscando primero algunos valores inválidos. Al arrojarlos a sabiendas desde su código, solo hace que sea más difícil para el código de llamada determinar si se lanzaron debido a algún error en el código, o simplemente porque decidió reutilizarlos para algo en su implementación.

Por supuesto, hay algunas excepciones (hah) a estas reglas. Si está creando algo que puede causar una excepción que coincida exactamente con una existente, entonces siéntase libre de usarlo, especialmente si está tratando de hacer coincidir algún comportamiento incorporado. Solo asegúrate 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 crear sus propios tipos de excepciones para excepciones esperadas específicas. Especialmente cuando escribe código de biblioteca, esto puede ser muy útil para separar las fuentes de excepción.