Как элегантно проверить, находится ли число в пределах диапазона? - PullRequest
129 голосов
/ 06 июля 2010

Как я могу сделать это элегантно с C # и .NET 3.5 / 4?

Например, число может быть между 1 и 100.

Я знаю простого if, если его будет достаточно;но ключевое слово в этом вопросе - элегантность.Это для моего игрушечного проекта не для производства.

Этот вопрос был не о скорости, а о красоте кода.Хватит говорить об эффективности и тому подобном;помните, что вы проповедуете хору.

Ответы [ 23 ]

116 голосов
/ 06 июля 2010

Есть много опций:

int x = 30;
if (Enumerable.Range(1,100).Contains(x))
    //true

if (x >= 1 && x <= 100)
    //true

Кроме того, проверьте это ТАК для опций регулярных выражений.

84 голосов
/ 06 июля 2010

Вы имеете в виду?

if(number >= 1 && number <= 100)

или

bool TestRange (int numberToCheck, int bottom, int top)
{
  return (numberToCheck >= bottom && numberToCheck <= top);
}
51 голосов
/ 06 июля 2010

Просто чтобы добавить шум, вы можете создать метод расширения:

public static bool IsWithin(this int value, int minimum, int maximum)
{
    return value >= minimum && value <= maximum;
}

, который позволит вам сделать что-то вроде ...

int val = 15;

bool foo = val.IsWithin(5,20);

При этом,это выглядит глупо, если сама проверка состоит из одной строки.

42 голосов
/ 06 июля 2010

Как уже говорили другие, используйте простой if.

Вы должны подумать о заказе.

* 1005 например *

1 <= x && x <= 100

легче читать, чем

x >= 1 && x <= 100
35 голосов
/ 20 сентября 2013

Вы можете уменьшить количество сравнений с двух до одного, используя некоторые математические.Идея состоит в том, что один из двух факторов становится отрицательным, если число лежит за пределами диапазона, и ноль, если число равно одной из границ:

Если границы включительно:

(x - 1) * (100 - x) >= 0

или

(x - min) * (max - x) >= 0

Если границы являются исключительными:

(x - 1) * (100 - x) > 0

или

(x - min) * (max - x) > 0

Однако в производственном коде я просто написал бы1 < x && x < 100, это легче понять.

16 голосов
/ 06 июля 2010

Немного злоупотребив методом расширения, мы можем получить следующее «элегантное» решение:

using System;

namespace Elegant {
    public class Range {
        public int Lower { get; set; }
        public int Upper { get; set; }
    }

    public static class Ext {
        public static Range To(this int lower, int upper) {
            return new Range { Lower = lower, Upper = upper };
        }

        public static bool In(this int n, Range r) {
            return n >= r.Lower && n <= r.Upper;
        }
    }

    class Program {
        static void Main() {
            int x = 55;
            if (x.In(1.To(100)))
                Console.WriteLine("it's in range! elegantly!");
        }
    }
}
16 голосов
/ 05 апреля 2017

Я предлагаю это:

public static bool IsWithin<T>(this T value, T minimum, T maximum) where T : IComparable<T> {
    if (value.CompareTo(minimum) < 0)
       return false;
    if (value.CompareTo(maximum) > 0)
       return false;
    return true;
}

Примеры:

45.IsWithin(32, 89)
true
87.2.IsWithin(87.1, 87.15)
false
87.2.IsWithin(87.1, 87.25)
true

и, конечно, с переменными:

myvalue.IsWithin(min, max)

Его легко читать (близко к человекуязык) и работает с любым сопоставимым типом (целые, двойные, пользовательские типы ...).

Важно, чтобы код был легко читаемым, потому что разработчик не будет тратить «мозговые циклы» на его понимание.В долгих сеансах кодирования потраченные впустую мозговые циклы утомляют разработчика раньше и склонны к ошибкам.

7 голосов
/ 06 июля 2010

Если это случайно, просто if это все, что вам нужно.Если это происходит во многих местах, вы можете рассмотреть следующие два:

  • PostSharp .Украсьте методы с атрибутами, которые «внедряют» код в метод после компиляции.Я не знаю точно, но я могу представить, что это может быть использовано для этого.

Что-то вроде:

[Between("parameter", 0, 100)]
public void Foo(int parameter)
{
}
  • Код контракта .Преимущество в том, что ограничения могут быть проверены во время компиляции, путем статической проверки вашего кода и мест, в которых он используется.
5 голосов
/ 06 июля 2010

Использование выражения && для объединения двух сравнений - это просто самый элегантный способ сделать это. Если вы попытаетесь использовать причудливые методы расширения и тому подобное, вы столкнетесь с вопросом: включать ли верхнюю границу, нижнюю границу или и то, и другое. Как только вы начинаете добавлять дополнительные переменные или изменять имена расширений, чтобы указать, что включено, ваш код становится длиннее и труднее для чтения (для подавляющего большинства программистов). Более того, такие инструменты, как Resharper, будут предупреждать вас, если ваше сравнение не имеет смысла (number > 100 && number < 1), чего они не будут делать, если вы используете метод ('i.IsBetween (100, 1)').

Единственный другой комментарий, который я хотел бы сделать, заключается в том, что если вы проверяете входные данные с намерением выдать исключение, вам следует рассмотреть возможность использования контрактов кода:

Contract.Requires(number > 1 && number < 100)

Это более элегантно, чем if(...) throw new Exception(...), и вы даже можете получить предупреждения во время компиляции, если кто-то попытается вызвать ваш метод, не убедившись, что число находится в границах первого.

5 голосов
/ 06 июля 2010
if (value > 1 && value < 100)
{
    // do work
}
else
{
    // handle outside of range logic
}
...