Как я могу сделать это изящно с C# и.NET 3.5/4?
Например, число может быть между 1 и 100.
Я знаю простое, если был бы достаточен; но ключевое слово к этому вопросу является элегантностью. Это для моего игрушечного проекта не для производства.
Это подвергает сомнению, не был о скорости, а о красоте кода. Прекратите говорить об эффективности и таком; помните, что Вы проповедуете хору.
Есть много вариантов:
int x = 30;
if (Enumerable.Range(1,100).Contains(x))
//true
if (x >= 1 && x <= 100)
//true
Кроме того, ознакомьтесь с этим сообщением SO , чтобы узнать о параметрах регулярных выражений.
В C, если эффективность использования времени имеет решающее значение, а целочисленные переполнения будут заворачиваться, можно сделать if ((unsigned)(value-min) <= (max-min)) ...
. Если 'max' и 'min' являются независимыми переменными, дополнительное вычитание для (max-min) будет тратить время, но если это выражение может быть предварительно вычислено во время компиляции, или если оно может быть вычислено один раз во время выполнения для проверки многих чисел на одинаковый диапазон, вышеприведенное выражение может быть вычислено эффективно даже в случае, когда значение находится в диапазоне (если большая доля значений будет ниже допустимого диапазона, может быть быстрее использовать if ((value >= min) && (value <= max)) ...
поскольку он завершится раньше, если значение меньше min).
Однако, прежде чем использовать подобную реализацию, проведите бенчмарк на своей целевой машине. На некоторых процессорах двухкомпонентное выражение может быть быстрее во всех случаях, поскольку два сравнения могут выполняться независимо, тогда как в методе вычитания и сравнения вычитание должно завершиться до выполнения сравнения.
Если это случайно, вам достаточно простого if
. Если это происходит во многих местах, вы можете рассмотреть следующие два:
Примерно так:
[Between("parameter", 0, 100)]
public void Foo(int parameter)
{
}
if (value > 1 && value < 100)
{
// do work
}
else
{
// handle outside of range logic
}
Немного злоупотребляя методом расширения, мы можем получить следующее "элегантное" решение:
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!");
}
}
}
Как говорили другие, используйте простое if.
Вам следует подумать об упорядочивании.
например,
1 <= x && x <= 100
легче читать, чем
x >= 1 && x <= 100
Вы имеете в виду?
if(number >= 1 && number <= 100)
или
bool TestRange (int numberToCheck, int bottom, int top)
{
return (numberToCheck >= bottom && numberToCheck <= top);
}
Чтобы добавить сюда шума, вы можете создать метод расширения:
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);
При этом это кажется глупым что делать, когда сама проверка - это всего одна строчка.
Новый поворот к старому любимому:
public bool IsWithinRange(int number, int topOfRange, int bottomOfRange, bool includeBoundaries) {
if (includeBoundaries)
return number <= topOfRange && number >= bottomOfRange;
return number < topOfRange && number > bottomOfRange;
}
Использование выражения &&
для объединения двух сравнений - это просто самый элегантный способ сделать это. Если вы попытаетесь использовать причудливые методы расширения и тому подобное, вы столкнетесь с вопросом, следует ли включать верхнюю границу, нижнюю границу или и то, и другое. Как только вы начнете добавлять дополнительные переменные или изменять имена расширений, чтобы указать, что включено, ваш код становится длиннее и труднее читается (для подавляющего большинства программистов). Кроме того, такие инструменты, как Resharper, предупредят вас, если ваше сравнение не имеет смысла ( number> 100 && number <1
), чего они не будут делать, если вы используете метод ('i.IsBetween (100 , 1) ').
Единственный другой комментарий, который я хотел бы сделать, это то, что если вы проверяете входные данные с намерением выбросить исключение, вам следует подумать об использовании контрактов кода:
Contract.Requires(number > 1 && number < 100)
Это более элегантно, чем if (... ) throw new Exception (...)
, и вы даже можете получить предупреждения во время компиляции, если кто-то попытается вызвать ваш метод, не убедившись, что число сначала находится в границах.