2010-07-04 12 views
21

En C#, a menudo tengo que limitar un valor entero a un rango de valores. Por ejemplo, si una aplicación espera un porcentaje, un número entero de una entrada de usuario no debe ser menor que cero o más de cien. Otro ejemplo: si hay cinco páginas webs a las que se accede a través Request.Params["p"], esperaba un valor de 1 a 5, no es 0 o 256 o 99999.¿Cómo forzar a un número a estar en un rango en C#?

menudo termino escribiendo un código bastante feo como:

page = Math.Max(0, Math.Min(2, page)); 

o incluso más feo:

percentage = 
    (inputPercentage < 0 || inputPercentage > 100) ? 
    0 : 
    inputPercentage; 

¿no hay una manera más inteligente de hacer tales cosas dentro de .NET Framework?

Sé que puedo escribir un método general int LimitToRange(int value, int inclusiveMinimum, int inlusiveMaximum) y usarlo en todos los proyectos, pero tal vez ya exista un método mágico en el marco?

Si tengo que hacerlo manualmente, ¿cuál sería la "mejor" (es decir, menos fea y más rápida) forma de hacer lo que estoy haciendo en el primer ejemplo? ¿Algo como esto?

public int LimitToRange(int value, int inclusiveMinimum, int inlusiveMaximum) 
{ 
    if (value >= inclusiveMinimum) 
    { 
     if (value <= inlusiveMaximum) 
     { 
      return value; 
     } 

     return inlusiveMaximum; 
    } 

    return inclusiveMinimum; 
} 
+7

Por lo general, se llama 'pinza': ver http://stackoverflow.com/questions/516500/is- there-a-canonical-name-for-a-function-combining-min-and-max y http://stackoverflow.com/questions/427477/fastest-way-to-clamp-a-real-fixed-floating- point-value y http://stackoverflow.com/questions/2683442/where-can-i-find-the-clamp-function-in-net y así sucesivamente. – ShreevatsaR

Respuesta

24

veo la respuesta de la marca y en su educación por un this:

public static class InputExtensions 
{ 
    public static int LimitToRange(
     this int value, int inclusiveMinimum, int inclusiveMaximum) 
    { 
     if (value < inclusiveMinimum) { return inclusiveMinimum; } 
     if (value > inclusiveMaximum) { return inclusiveMaximum; } 
     return value; 
    } 
} 

Uso:

int userInput = ...; 

int result = userInput.LimitToRange(1, 5) 

Ver: Extension Methods

+4

Tenga en cuenta que el uso de métodos de extensión no tiene que ser necesariamente algo bueno. Es solo otra herramienta de programación y tiene sus aplicaciones. Ponlo en el lugar o contexto incorrecto y terminarás escribiendo un código ilegible. – Trap

7

Una forma alternativa de escribir la función LimitToRange es la siguiente.

public int LimitToRange(int value, int inclusiveMinimum, int inclusiveMaximum) 
{ 
    if (value < inclusiveMinimum) { return inclusiveMinimum; } 
    if (value > inclusiveMaximum) { return inclusiveMaximum; } 
    return value; 
} 

Creo que esto es un poco más fácil de entender sin dejar de ser eficiente.

+3

@MainMa: si el valor está dentro del rango, debe realizar dos comprobaciones, sin importar el orden en que coloque sus estados de cuenta. En cuanto al rendimiento, todas las respuestas deben ser iguales. – dtb

+1

Usando <= and > = puede evitar el segundo cheque o un salto en casos extremos :-) – IamIC

42

Esta operación se denomina 'Pinza' y suele escribirse así:

public static int Clamp(int value, int min, int max) 
{ 
    return (value < min) ? min : (value > max) ? max : value; 
} 
+3

Me gusta el nombre Clamp. Incluso el Microsoft.Xna.Framework tiene un método Clamp :) – Syd

+3

Clamp es el nombre normal. Ver la especificación OpenCL. – IamIC

+7

Ps. Este código es más eficiente con <= and > =, en lugar de < and >. :-) – IamIC

3

No, no hay ningún método para eso incorporado en el marco. Supongo que fue omitido porque ya tiene Min y Max, por lo que puede lograrlo usándolos.

Si escribe su propio método para ello, no importa mucho cómo lo escriba. Si usa las declaraciones if o el operador condicional ?, de todos modos se compilará prácticamente con el mismo código.

+0

Esto suena como un argumento para detener todos los esfuerzos en nuevos y/o actualizar los lenguajes de programación si "ya tenemos [las herramientas]" !! ... teníamos las herramientas para escribir nuestras propias funciones de Min Max, entonces ¿por qué nos las dieron? – noelicus

2

Me gusta la respuesta de Guffa, pero me sorprende que nadie haya publicado una solución usando Min/Max.

public int LimitInclusive(int value, int min, int max) 
{ 
    return Math.Min(max, Math.Max(value, min)); 
} 
+0

Tal vez usar 'Min' y' Max' cada vez tendría un impacto en el rendimiento? –

20

Un método mucho más limpio que funcionará con algo más que números enteros (tomado de mi propia biblioteca de código compartido):

public static T Clamp<T>(T value, T min, T max) where T : IComparable<T> 
{ 
    if (value.CompareTo(min) < 0) 
     return min; 
    if (value.CompareTo(max) > 0) 
     return max; 

    return value; 
} 
+8

Eso arroja una NullReferenceException si 'value' es' null'. Mejor utilice un IComparer (por ejemplo, 'Comparer .Default') en su lugar. http://msdn.microsoft.com/en-us/library/azhsac5f.aspx – dtb

3

para fijar los valores sin dar a los usuarios cualquier comentario que el valor introducido por ellos están equivocados, en general, podría no ser una gran idea (en mi humilde opinión). Esto podría conducir a errores sutiles más adelante, que son difíciles de depurar, especialmente cuando los valores mínimos/máximos se determinan en tiempo de ejecución.

Piense en esto. Tiene $ 100 en su cuenta bancaria y desea transferir $ 150 a su amigo. ¿Le gustaría que su sistema bancario arroje un InsufficientFundsException o entre en una discusión con su amigo que transfirió $ 150 pero recibió solo $ 100 (suponiendo que el banco bloqueó el monto de la transferencia a 100 porque no tenía fondos suficientes)

Dicho esto, también debes mirar los contratos de código.

public void MyFunction (Type input) 
{ 
    Contract.Requires(input > SomeReferenceValue); 
    Contract.Requires (input < SomeOtherReferencValue); 

} 

Esto obligará a la entrada del usuario a estar dentro del rango.

1

Me gusta el nombre de la abrazadera. Yo sugeriría la siguiente clase

public class MathHelper 
{ 
    public static int Clamp (int value,int min,int max) 
    { 
      // todo - implementation 
    } 
    public static float Clamp (float value,float min,float max) 
    { 
      // todo - implementation 
    } 
) 

o si desea utilizar los genéricos, a continuación,

public class MathHelper 
{ 
    public static T Clamp<T> (T value, T min, T max) where T : IComparable 
    { 
     // todo - implementation 
     T output = value; 
     if (value.CompareTo(max) > 0) 
     { 
      return max; 
     } 
     if (value.CompareTo(min) < 0) 
     { 
      return min; 
     } 
     return output; 
    } 
} 
Cuestiones relacionadas