2010-03-26 7 views
12

tengo una clase que envuelve Lista <>¿Debo arrojar mi propia ArgumentOutOfRangeException o permitir que una burbuja suba desde abajo?

tengo GetValue por el método de índice:

public RenderedImageInfo GetValue(int index) 
    { 
     list[index].LastRetrieved = DateTime.Now; 
     return list[index]; 
    } 

Si el usuario solicita un índice que está fuera de rango, esto generará un ArgumentOutOfRangeException.

¿Debo dejar que esto suceda o verificarlo y lanzar el mío? es decir,

public RenderedImageInfo GetValue(int index) 
    { 
     if (index >= list.Count) 
     { 
      throw new ArgumentOutOfRangeException("index"); 
     } 
     list[index].LastRetrieved = DateTime.Now; 
     return list[index]; 
    } 

En el primer escenario, el usuario tendría una excepción de la lista interna, que rompe mi objetivo programación orientada a objetos del usuario sin necesidad de saber acerca de los objetos subyacentes.

Pero en el segundo caso, siento que estoy agregando código redundante.

Editar:
Y ahora que lo pienso, ¿qué pasa con una tercera escenario, donde cojo la excepción interna, modificarlo y volver a lanzar él?

+0

Sugeriría encarecidamente en contra de su tercer escenario. – TrueWill

+0

@TrueWill, ¿puede indicar una razón por la cual? –

+5

No es bueno modificar una excepción existente: eso realmente será un comportamiento inesperado (y mucho menos imposible sin reflexión, ya que no hay un establecedor de propiedades para ParamName): http://msdn.microsoft.com/en-us/library/system .argumentexception.paramname.aspx –

Respuesta

12

Debe lanzar su propia, por un par de razones:

  1. Puede establecer explícitamente la appropriate parameter name in the constructor.De esta manera, la excepción tiene la información de parámetro adecuada para el argumento que está fuera de rango.
  2. (Menor) La excepción de la lista interna tendrá un rastro de pila no válido en lo que respecta a su usuario. Al construir una nueva excepción, puede obtener el seguimiento de la pila mostrando que su método es el que es inapropiado, lo que será más fácil para la depuración de su usuario.

En cuanto a atrapar y modificar la excepción interna, no lo recomendaría necesariamente. Si la excepción es potencialmente potencialmente útil, debe usar el InnerException de su nueva excepción para propocionar esta información.

En este ejemplo (ArgumentOutOfRangeException), el hecho de que haya una lista interna se debe mantener como un detalle de implementación, y no hay ninguna razón para que el usuario vea esa información.

+0

Decidí que si arrojaba el mío, o si volvía a lanzar el inferior, al menos agregaría el nombre de param (aunque en este método solo hay uno, así que es cierto que param es culpable) –

+0

@Neil: Acabo de escribir editado para responder esa pregunta, también. –

+0

@Neil: no hay forma de "agregar" el parámetro a una excepción existente. The List tendrá uno incluido, pero no confiaría en que siga siendo el mismo ... Dicho esto, NUNCA modificaría una excepción en un controlador ... –

2

Está bien permitir que la excepción salte en este caso.

edición

Me han pedido para actualizar mi respuesta para incluir algunas de las respuestas ...

Podría decirse que agarrar la excepción y Regeneración de ella como una combinación interna es más robusto, en ese lo aísla de los cambios y crea una interfaz más consistente. Una vez dicho esto, el beneficio puede ser muy pequeño, sin límite en ninguno, en un entorno donde el desarrollador tiene acceso a todo el código. Además, cualquier pequeño beneficio que obtengamos no es gratis. El código adicional de manejo de errores agrega complejidad, y debe ser probado para garantizar que funcione. También aumenta el riesgo de romper el método durante el mantenimiento, ya que la funcionalidad básica del método podría ser oscurecida por todos los blindajes.

Entonces, ¿vale la pena? Depende. Todo se reduce al análisis costo/beneficio, que solo puede hacerse para un contexto específico. Para una API pública, como AlphaFS, los beneficios pueden exceder los costos. Para uso interno en código que no está diseñado para una reutilización significativa, probablemente no lo es. Ese es el contexto de mi respuesta original, que aún defiendo. Además, como señaló Hightechrider, puede haber otras tecnologías, como los contratos de codificación, que producen el mismo beneficio pero a un costo menor, cambiando la ecuación en favor de la solidez.

Como siempre, estoy abierto a un desacuerdo razonado. Sin embargo, sugiero que todos intentemos evitar el pensamiento único para todos.

edición

Sólo para que quede claro que no estoy loco cuando digo que el código de control de errores es propenso a errores, echar un vistazo a la pregunta original y dime si puede detectar la error. Ofrezco un +1 si lo haces.

+0

Reed hizo algunos comentarios interesantes acerca de por qué hay veces que desea lanzar su propia excepción, pero sería útil si el infractor le explicara por qué no está bien * EN ESTE CASO *. –

+0

No he votado negativamente, pero creo que es irónico que pidas una razón a un infractor, cuando tu respuesta no tenía ningún razonamiento detrás. ** ¿POR QUÉ ** está bien en este caso? –

+1

Bueno, si el infractor me hubiera preguntado POR QUÉ, habría tenido la oportunidad de responder. Tal como está, he respondido a través de mis respuestas a otros. El resumen es que no hay beneficio, pero hay un costo. De cualquier forma, se lanza la misma excepción, que difiere solo en la profundidad de su traza de pila. ¿Por qué complicar el código sin motivo? –

3

Si estás en .NET 2.0 o superior, puede utilizar the inner exception, así:

public RenderedImageInfo GetValue(int index) 
{ 
    try { 
     list[index].LastRetrieved = DateTime.Now; 
     return list[index]; 
    } catch (ArgumentOutOfRangeException ex) { 
     throw new ArgumentOutOfRangeException("index", ex); 
    } 
} 

De esta manera, el usuario verá principalmente a su excepción, pero es posible profundizar más si (o ellos) quieren.

Editar: Veo ahora que InnerException ha sido compatible desde .NET 1.0, es solo ese constructor que es nuevo. No veo manera de configurar realmente el InnerException para un ArgumentOutOfRangeException en .NET antes de 2.0. ¿Acaso lo olvidaron o el código que escribí arriba está en contra del uso previsto?

+0

+1 para cubrir todas las bases. –

+0

Creo que esto es a lo que me refería cuando dije agregar/modificar el nombre de param en la excepción. Pero, en general, creo que la respuesta de Reed de lanzar una nueva es mejor. +1 para completar, sin embargo. –

+0

Esta no es una buena solución general. ¿Qué haces cuando necesitas verificar una Lista <> y luego otra? –

3

... breaks m [y] OOP objetivo del usuario que no necesita saber acerca de los objetos subyacentes.

Lanzar la misma excepción no hace nada para la encapsulación. O bien su contrato (implícita/documentada - ya que no tenemos excepciones marcadas o DbC) declara que lanzará una excepción ArgumentOutOfRange en este caso o no. Cómo se genera esa excepción y cómo se ve el seguimiento de la pila es irrelevante para la persona que llama.

Si mueve su implementación interna a algo que no lanzar una excepción ArgumentOutOfRange, entonces usted necesita para lanzar uno a sí mismo para cumplir su contrato (o hacer un cambio importante en el contrato).

Stack Traces (y el nombre de param) es para la depuración del tipo, no para el acceso programático. A menos que haya algún problema de seguridad, no hay que preocuparse por dejar que se "filtren".

Por cierto, el consejo (que puede estar pensando) de envolver excepciones proviene de un escenario más abstracto. Considere un IAuthenticationService que lanza si un usuario no puede Login,

Si hay tanto un LdapAuthenticationService y una aplicación DatabaseAuthenticationService, entonces usted tendría que ponerse al tanto LdapDirectoryException y SqlException para determinar un inicio de sesión fallido. Cuando se realiza una tercera implementación, también debe agregar sus tipos de excepción específicos. Por todos los implementadores que envuelven su excepción específica en un FailedAuthenticationException, solo tiene el único tipo del que preocuparse.

Aún así sería una buena idea incluir la excepción original en InnerException, ya que ayuda en la depuración.

Espero que pueda ver la diferencia entre este escenario y el suyo: en su caso, solo está lanzando el mismo tipo de excepción para que no haya diferencia.

Dicho todo esto, si fuera para una biblioteca, entonces lo verificaría y arrojaría. Pero no por la pureza de los POO, sino porque hace que el contrato sea explícito y es menos probable que se modifique inadvertidamente. Si estuviera usando [T | B] DD, entonces solo escribiría una prueba y dejaría que se lanzara el List - la prueba explicita el contrato.

Cuestiones relacionadas