2010-07-24 8 views
6

Me gustaría restringir el valor de un parámetro numérico en un constructor dentro de un cierto rango.Restringir el valor de un parámetro en un constructor AT TIEMPO DE DISEÑO

sé la forma convencional es hacer algo como lo siguiente:

public class Foo 
{ 
    public int MaxAmount { get; } 
    public int Amount { get; set; } 

    public Foo(int amount) 
    { 
     if (amount > MaxAmount) { Amount = MaxAmount; } 
     else if (amount < 1) { Amount = 1; } 
     else { Amount = amount; } 
    } 
} 

Pero lo que no me gusta de esto es que la persona que llama no sabe cuando la propiedad se establece en algo distinto lo que se especificó. Podría devolver una excepción en lugar de silenciar el valor en silencio, pero eso no es muy amigable.

Lo que me gustaría es algo parecido a esto:

public Foo(int(1, this.MaxAmount) amount) // Where int(minimumValue, maximumValue) 
{ 
    Amount = amount; 
}

en el que uno ni siquiera sería capaz de crear una instancia de Foo con un valor inaceptable - el marco lo impediría.

¿Es posible algo como esto?

EDITAR para mayor claridad:

lo que busco es un medio por el cual el parámetro en sí puede llevar y comunicar la información sobre sus limitaciones - en un 'cuece en' moda que podría, por ejemplo, superficie en Intellisense cuando escribió la llamada. Por lo tanto, evitaría el trabajo de intentar crear instancias de la clase si los valores de los parámetros no eran válidos.

Si, por ejemplo, el programa se está ejecutando y el usuario escribe un número (N) y presiona un botón que crea un nuevo Foo con una cantidad ilegal de N, ahora tengo una excepción y algo para depurar y fijar. ¿Por qué incluso permitirlo en primer lugar? Si Foo ha sido explícitamente definido como teniendo un límite superior de 4 para su propiedad Amount, ¿por qué permitir que el desarrollador escriba Foo (5) cuando pude haberle informado que el valor que está pasando no es válido en el momento en que él ¿lo escribió?

Si hay algo de azúcar sintáctica, como ParameterConstraint o algo así, eso es manejado por el Framework para que yo no tenga que aplicar el mío en todas las clases que escribo, creo que sería muy útil.

Respuesta

7

Puede hacerlo mediante la comprobación de contrato estático con Code Contracts (solo Premium: la edición estándar solo ofrece verificación de contratos en tiempo de ejecución).

La sintaxis es simplemente

public Foo(int amount) { 
    Contract.Requires(amount < MaxAmount); 
    ... 
} 

(Requiere) contratos se evalúan mediante la comprobación de que los argumentos se ve limitada al llamar al método. En su instancia, será difícil evaluar el argumento del constructor con el campo de instancia MaxAmount, porque no puede verificar ese valor de antemano. (Haga que MaxValue estético para resolver esto).

Ejemplo de dicha llamada.

int val = _getFromSomewhere(); 
var foo = new Foo(val); 
//This May produce compile time error 
// because the contract checker cannot prove you contract is met. 

La solución sería asegurarse de poner la restricción donde se realiza la llamada.

int val = _getFromSomewhere(); 
if (val < Foo.MaxAmount) 
    var foo = new Foo(val); 
    //Will always compile fine, because contract is met. 

Al instalar los contratos, el corrector estático no está activada de forma predeterminada. Las propiedades de su proyecto tendrán una pestaña adicional donde puede configurar las opciones de contrato y habilitar la comprobación estática.

+1

Tenga en cuenta que usar 'Contract.Requires' no es suficiente. Aún necesita un 'if (...) lanzar new ArgumentOutOfRangeException()'. –

9

Podría devolver una excepción en lugar de apretar silenciosamente el valor, pero eso no es muy amigable.

Say what? ¿Qué quieres decir con "amistoso"? La persona que llama no es tu amiga, es otra pieza de código que intenta establecer un valor fuera de rango. Al desarrollador que escribió el código se le debe decir inmediatamente que está haciendo algo mal.

¡Lance una excepción!

+1

Quiero * informar * a la persona que llama que el valor no es válido, pero sin hacer el trabajo de intentar crear una instancia de la clase. Creo que sería bueno tener la respuesta Intellisense que no es válida, por ejemplo. –

1

Cualquiera de lanzar la excepción o proporcionar una propiedad estática para validar la cantidad

public static bool ValidateAmount(int amount) 
{ 
    if(amount > MaxAmount) 
     return false; 
    return true; 
} 
2

Usted tendrá que ajustar el parámetro en un nuevo tipo a continuación. conoce cuál es su cantidad máxima, y ​​es int.MaxValue. Si realmente es el caso que el parámetro en sí mismo conoce su propia cantidad máxima, y ​​que no es algo específico de la clase Foo, entonces tendrá que crear otro tipo que verifique el monto que se le haya pasado. Tal como está, la firma del constructor de Foo acepta cualquier estructura de datos int.

1

No estoy seguro de si esto funciona para los tipos de propiedades en C#, pero es posible que pueda definir una enumeración que contenga todos los valores aceptables y luego establezca el tipo de datos de la propiedad en esa enumeración. Eso obligaría a la persona que llama a usar la enumeración y, por lo tanto, sabrá qué valores son aceptables. Por supuesto, si tiene muchos valores en el rango aceptable, la enumeración sería difícil de manejar.

Cuestiones relacionadas