Как заставить число быть в диапазоне в C #?

c# .net performance math

50690 просмотра

8 ответа

В C # мне часто приходится ограничивать целочисленное значение диапазоном значений. Например, если приложение ожидает процент, целое число из пользовательского ввода не должно быть меньше нуля или больше ста. Другой пример: если есть пять веб-страниц, к которым осуществляется доступ Request.Params["p"], я ожидаю значение от 1 до 5, а не 0, 256 или 99999.

Я часто заканчиваю тем, что пишу довольно уродливый код вроде:

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

или даже хуже

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

Разве нет более разумного способа делать такие вещи в .NET Framework?

Я знаю, что могу написать общий метод int LimitToRange(int value, int inclusiveMinimum, int inlusiveMaximum)и использовать его в каждом проекте, но, может быть, в фреймворке уже есть магический метод?

Если мне нужно сделать это вручную, каков будет «лучший» (то есть менее уродливый и более быстрый) способ сделать то, что я делаю в первом примере? Что-то вроде этого?

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

        return inlusiveMaximum;
    }

    return inclusiveMinimum;
}
Автор: Arseni Mourzenko Источник Размещён: 12.11.2019 09:22

Ответы (8)


27 плюса

Решение

Я вижу ответ Марка и поднимаю его 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;
    }
}

Использование:

int userInput = ...;

int result = userInput.LimitToRange(1, 5)

См .: Методы расширения

Автор: dtb Размещён: 04.07.2010 11:57

56 плюса

Эта операция называется «Зажим» и обычно пишется так:

public static int Clamp( int value, int min, int max )
{
    return (value < min) ? min : (value > max) ? max : value;
}
Автор: Trap Размещён: 04.07.2010 11:53

27 плюса

Гораздо более чистый метод, который будет работать не только с целыми числами (взят из моей собственной библиотеки общего кода):

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;
}
Автор: MikeP Размещён: 05.07.2010 12:09

7 плюса

Альтернативный способ написания вашей LimitToRangeфункции заключается в следующем.

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

Я думаю, что это немного легче понять, но все же эффективно.

Автор: Mark Byers Размещён: 04.07.2010 11:53

7 плюса

Мне нравится ответ Гуффы, но я удивлен, что никто еще не опубликовал решение, использующее Мин / Макс.

public int LimitInclusive(int value, int min, int max)
{
    return Math.Min(max, Math.Max(value, min));
}
Автор: Ed S. Размещён: 05.07.2010 12:06

3 плюса

Нет, нет никакого метода для этого, встроенного в фреймворк. Я полагаю, что это было опущено, потому что у вас уже есть Minи Max, так что вы можете сделать это, используя их.

Если вы пишете свой собственный метод для него, не имеет большого значения, как вы его пишете. Если вы используете ifоператоры или условный оператор ?, он все равно будет скомпилирован во многом в тот же код.

Автор: Guffa Размещён: 04.07.2010 11:59

3 плюса

Зажимать значения, не давая пользователям никакой обратной связи о том, что введенное ими значение неверно, в общем, может быть не очень хорошая идея (ИМХО). Это может впоследствии привести к незначительным ошибкам, которые трудно отладить, особенно если во время выполнения определены минимальные / максимальные значения.

Подумай об этом. У вас есть 100 долларов на вашем банковском счете, и вы хотите перевести 150 долларов своему другу. Хотели бы вы, чтобы ваша банковская система выдавала InsufficientFundsExceptionили обсуждала с вашим другом, что вы перечислили 150 долларов, но он получил только 100 долларов (при условии, что банк ограничил сумму перевода 100, поскольку у вас не было достаточно средств)

Тем не менее, вы также должны посмотреть на контракты кода.

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

}

Это заставит пользовательский ввод находиться в пределах диапазона.

Автор: ram Размещён: 05.07.2010 01:04

1 плюс

Мне нравится название зажима. Я бы предложил следующий класс

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 
    }
)

или если вы хотите использовать дженерики, то

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;
     } 
}
Автор: Syd Размещён: 05.07.2010 02:12
32x32