我如何用c#优雅地做到这一点?

例如,一个数字可以是1到100之间。

我知道一个简单的if (x >= 1 && x <= 100)就足够了;但是有很多语法糖和新特性不断添加到c# /。Net这个问题是关于更习惯的(一个可以称之为优雅的)写法。

性能不是问题,但请在非O(1)的解决方案中添加性能说明,因为人们可能会复制粘贴建议。


当前回答

关于优雅,最接近数学符号(a <= x <= b)的方法略微提高了可读性:

public static bool IsBetween(this int value, int min, int max)
{
    return min <= value && value <= max;
}

为了进一步说明:

public static bool IsOutside(this int value, int min, int max)
{
    return value < min || max < value;
}

其他回答

你的意思是?

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

or

bool TestRange (int numberToCheck, int bottom, int top)
{
  return (numberToCheck >= bottom && numberToCheck <= top);
}

这些是一些可以提供帮助的扩展方法

  public static bool IsInRange<T>(this T value, T min, T max)
where T : System.IComparable<T>
    {
        return value.IsGreaterThenOrEqualTo(min) && value.IsLessThenOrEqualTo(max);
    }


    public static bool IsLessThenOrEqualTo<T>(this T value, T other)
         where T : System.IComparable<T>
    {
        var result = value.CompareTo(other);
        return result == -1 || result == 0;
    }


    public static bool IsGreaterThenOrEqualTo<T>(this T value, T other)
         where T : System.IComparable<T>
    {
        var result = value.CompareTo(other);
        return result == 1 || result == 0;
    }

我使用下一个“优雅”的解决方案:

using static System.Linq.Enumerable;

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

来自微软文档

using static指令适用于任何具有静态成员(或嵌套类型)的类型,即使它也具有实例成员。但是,实例成员只能通过类型实例调用。

你可以访问一个类型的静态成员,而不需要用类型名限定访问:

但这对许多人来说并不简单,因为Enumerable。Range有第一个参数start和第二个参数count。 所以这种检查可能在特定情况下有用,比如当你使用Enumerable时。范围的foreach循环,在开始之前,您想知道,如果循环将执行。

例如:

        int count = 100;
        int x = 30;

        if (!Range(1, count).Contains(x)) {
            Console.WriteLine("Do nothing!");
            return;
        }

        foreach (var i in Range(1, count)) {
            // Some job here
        }

因为所有其他答案都不是我发明的,这里只是我的实现:

public enum Range
{
    /// <summary>
    /// A range that contains all values greater than start and less than end.
    /// </summary>
    Open,
    /// <summary>
    /// A range that contains all values greater than or equal to start and less than or equal to end.
    /// </summary>
    Closed,
    /// <summary>
    /// A range that contains all values greater than or equal to start and less than end.
    /// </summary>
    OpenClosed,
    /// <summary>
    /// A range that contains all values greater than start and less than or equal to end.
    /// </summary>
    ClosedOpen
}

public static class RangeExtensions
{
    /// <summary>
    /// Checks if a value is within a range that contains all values greater than start and less than or equal to end.
    /// </summary>
    /// <param name="value">The value that should be checked.</param>
    /// <param name="start">The first value of the range to be checked.</param>
    /// <param name="end">The last value of the range to be checked.</param>
    /// <returns><c>True</c> if the value is greater than start and less than or equal to end, otherwise <c>false</c>.</returns>
    public static bool IsWithin<T>(this T value, T start, T end) where T : IComparable<T>
    {
        return IsWithin(value, start, end, Range.ClosedOpen);
    }

    /// <summary>
    /// Checks if a value is within the given range.
    /// </summary>
    /// <param name="value">The value that should be checked.</param>
    /// <param name="start">The first value of the range to be checked.</param>
    /// <param name="end">The last value of the range to be checked.</param>
    /// <param name="range">The kind of range that should be checked. Depending on the given kind of range the start end end value are either inclusive or exclusive.</param>
    /// <returns><c>True</c> if the value is within the given range, otherwise <c>false</c>.</returns>
    public static bool IsWithin<T>(this T value, T start, T end, Range range) where T : IComparable<T>
    {
        if (value == null)
            throw new ArgumentNullException(nameof(value));

        if (start == null)
            throw new ArgumentNullException(nameof(start));

        if (end == null)
            throw new ArgumentNullException(nameof(end));

        switch (range)
        {
            case Range.Open:
                return value.CompareTo(start) > 0
                       && value.CompareTo(end) < 0;
            case Range.Closed:
                return value.CompareTo(start) >= 0
                       && value.CompareTo(end) <= 0;
            case Range.OpenClosed:
                return value.CompareTo(start) > 0
                       && value.CompareTo(end) <= 0;
            case Range.ClosedOpen:
                return value.CompareTo(start) >= 0
                       && value.CompareTo(end) < 0;
            default:
                throw new ArgumentException($"Unknown parameter value {range}.", nameof(range));
        }
    }
}

然后你可以这样使用它:

var value = 5;
var start = 1;
var end = 10;

var result = value.IsWithin(start, end, Range.Closed);

当检查一个“数字”是否在一个范围内时,你必须清楚你的意思,两个数字相等意味着什么?一般来说,你应该把所有浮点数包装在一个所谓的“epsilon球”中,这是通过选择一个小的值来完成的,如果两个值如此接近,它们就是相同的。

    private double _epsilon = 10E-9;
    /// <summary>
    /// Checks if the distance between two doubles is within an epsilon.
    /// In general this should be used for determining equality between doubles.
    /// </summary>
    /// <param name="x0">The orgin of intrest</param>
    /// <param name="x"> The point of intrest</param>
    /// <param name="epsilon">The minimum distance between the points</param>
    /// <returns>Returns true iff x  in (x0-epsilon, x0+epsilon)</returns>
    public static bool IsInNeghborhood(double x0, double x, double epsilon) => Abs(x0 - x) < epsilon;

    public static bool AreEqual(double v0, double v1) => IsInNeghborhood(v0, v1, _epsilon);

有了这两个辅助,并假设任何数字都可以转换为double而不需要所需的精度。现在需要的是一个枚举和另一个方法

    public enum BoundType
    {
        Open,
        Closed,
        OpenClosed,
        ClosedOpen
    }

另一种方法如下:

    public static bool InRange(double value, double upperBound, double lowerBound, BoundType bound = BoundType.Open)
    {
        bool inside = value < upperBound && value > lowerBound;
        switch (bound)
        {
            case BoundType.Open:
                return inside;
            case BoundType.Closed:
                return inside || AreEqual(value, upperBound) || AreEqual(value, lowerBound); 
            case BoundType.OpenClosed:
                return inside || AreEqual(value, upperBound);
            case BoundType.ClosedOpen:
                return inside || AreEqual(value, lowerBound);
            default:
                throw new System.NotImplementedException("You forgot to do something");
        }
    }

现在,这可能远远超过了您想要的,但它使您不必一直处理舍入问题,并试图记住一个值是否被舍入到哪个位置。如果你需要,你可以很容易地将它扩展到任意的情况并允许变化。