2009-03-11 14 views
47

Tengo una propiedad de cadena que tiene un requisito de longitud máxima porque los datos están vinculados a una base de datos. ¿Qué excepción debo lanzar si la persona que llama intenta establecer una cadena que excede esta longitud?¿Qué excepción lanzar de un organizador de propiedades?

Por ejemplo, este código C#:

public string MyProperty 
{ 
    get 
    { 
     return _MyBackingField; 
    } 
    set 
    { 
     if (value.Length > 100) 
      throw new FooException("MyProperty has a maximum length of 100."); 

     _MyBackingField = value; 
    } 
} 

que considera ArgumentException, pero simplemente no me parece bien. Técnicamente, es una función - MyProperty_set(string value) - por lo que se puede crear un caso para ArgumentException, pero no se está llamando como una función a los ojos del consumidor: está en el lado derecho de un operador de asignación.

Esta pregunta probablemente también podría extenderse para incluir todos los tipos de validación de datos realizados en los establecedores de propiedades, pero estoy particularmente interesado en el caso anterior.

Respuesta

44

echar un vistazo a mscorlib.dll con reflector, en una situación similar, como Microsoft System.String.StringBuilder.Capacity utilizar ArgumentOutOfRangeException() similar a:

public int PropertyA 
{ 
    get 
    { 
     return //etc... 
    } 
    set 
    { 
     if (condition == true) 
     { 
      throw new ArgumentOutOfRangeException("value", "/* etc... */"); 
     } 
     // ... etc 
    } 
} 
+1

Por cierto, mono lanza una excepción ArgumentException en este caso ... –

+13

"ArgumentOutOfRangeException - La excepción que se produce cuando el valor de un argumento está fuera del rango de valores permitido definido por el método invocado " .... imo, Mono debería arreglar su código. –

-1

Puede usar InvalidOperationException. Eso es un compromiso. No me molestaría en usar una ArgumentException tampoco.

16

Para mí ArgumentException (o un niño) tiene más sentido, porque el argumento (valor) que proporcionó no es válido, y esto es para lo que se creó ArgumentException.

10

No lanzaría ninguna excepción. Más bien, permitiría una cadena de cualquier longitud y luego tendré un método "Validate" separado en la clase a la que se llama antes de guardar. Hay una serie de escenarios, especialmente si utiliza enlaces de datos donde arrojar excepciones de los responsables de la creación de la propiedad puede desordenarlo.

El problema con arrojar excepciones de los establecedores de propiedades es que los programadores se olvidan de atraparlos. Depende de cuán limpio usted espera que sean los datos que obtiene. En este caso, esperaría que las longitudes de cadena largas sean comunes, no excepcionales y, como tal, el uso de una excepción sería "control de flujo con excepciones".

citar Design Guidelines for Developing Class Libraries del Microsoft:

No utilizar excepciones para el flujo normal de de control, si es posible. Excepto por las fallas del sistema y las operaciones con condiciones de carrera potenciales, los diseñadores de framework deben diseñar API para que los usuarios de puedan escribir código que no incluya excepciones. Por ejemplo, puede proporcionar una forma de comprobar las condiciones previas antes de llamar a un miembro para que los usuarios puedan escribir código que no arroje excepciones .

+4

Aunque personalmente no estoy de acuerdo (la validación es el trabajo del colocador después de todo; de lo contrario, no tiene sentido tener nada más que simple campo = valor; campo de retorno; getters/setters) Me gusta que plantee el punto de DataBinding que de hecho puede meterlo en un lío –

+1

Excepción lanzando en setters de propiedad está bien hacer, yo no lanzaría excepciones en getters de propiedad. –

+0

Retrasar el lanzamiento de una excepción no le permitirá atrapar el infractor. si un programador se olvida de atrapar una excepción, saltará a su cara en lugar de burbujear inadvertidamente. – Trap

6

¿Recuerda cuántos problemas en informática se resuelven agregando un nivel extra de indirección?

Un enfoque sería crear un nuevo tipo, FixedLengthString, por ejemplo. Sería casos del tipo que que validan las longitudes de las cadenas con las que se inicializan, con un operador de conversión para realizar una conversión de tipo desde una cadena simple.Si su creador de propiedades toma un tipo como su argumento, cualquier violación se convertiría en una excepción de conversión de tipo en lugar de una excepción de argumento/propiedad.

En la práctica, rara vez hago esto. Huele un poco a tomar OO demasiado lejos, pero en algunos casos puede ser una técnica útil, así que lo menciono aquí para completar.

+2

¿Cómo lidiaría con pasar un conjunto FixedLengthString con un máximo de 100 caracteres a una propiedad que requiere un FixedLengthString configurado con un máximo de 50 caracteres? –

-2

Trate de usar las excepciones existentes siempre que sea posible. En este caso, use InvalidOperationException porque el valor entrante está llevando el objeto a un estado incoherente. Se pueden crear excepciones personalizadas cuando se necesita un manejo específico con la excepción personalizada. En este caso, solo lanza una excepción con algo de texto, así que use InvalidOperationException.

Al lanzar InvalidOperationException muestra el valor que se ha pasado a este setter.

+0

Por supuesto, puede tener lo mejor de ambos mundos y crear su propio tipo de excepción que se deriva de, digamos, InvalidOperationException. Por supuesto, todavía paga un poco en código adicional y complejidad del código. Es un costo pequeño pero, después de pesarlo, aún puede considerar que no vale la pena. – philsquared

+2

InvalidOperationException no se debe generar en este caso. Lo que está mal es el valor, no la operación de establecer el valor. – Trap

5
public IPAddress Address 
{ 
    get 
    { 
     return address; 
    } 
    set 
    { 
     if(value == null) 
     { 
      throw new ArgumentNullException("value"); 
     } 
     address = value; 
    } 
} 

través MSDN

+0

Buen punto, aunque esto es específico para el caso nulo. Sin embargo, sí admite el uso de la serie 'ArgumentException', por lo que +1 para la referencia. –

Cuestiones relacionadas