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

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

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

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


当前回答

优雅是因为它不需要确定两个边界值中哪个先大。它也不包含分支。

public static bool InRange(float val, float a, float b)
{
    // Determine if val lies between a and b without first asking which is larger (a or b)
    return ( a <= val & val < b ) | ( b <= val & val < a );
}

其他回答

我不知道,但我用这个方法:

    public static Boolean isInRange(this Decimal dec, Decimal min, Decimal max, bool includesMin = true, bool includesMax = true ) {

    return (includesMin ? (dec >= min) : (dec > min)) && (includesMax ? (dec <= max) : (dec < max));
}

这是我使用它的方式:

    [TestMethod]
    public void IsIntoTheRange()
    {
        decimal dec = 54;

        Boolean result = false;

        result = dec.isInRange(50, 60); //result = True
        Assert.IsTrue(result);

        result = dec.isInRange(55, 60); //result = False
        Assert.IsFalse(result);

        result = dec.isInRange(54, 60); //result = True
        Assert.IsTrue(result);

        result = dec.isInRange(54, 60, false); //result = False
        Assert.IsFalse(result);

        result = dec.isInRange(32, 54, false, false);//result = False
        Assert.IsFalse(result);

        result = dec.isInRange(32, 54, false);//result = True
        Assert.IsTrue(result);
    }

使用内置的Range结构体(c# 8+),我们可以创建一个扩展方法来检查索引是否在原始范围内。

public static bool IsInRangeOf(this Range range, Index index)
{
   return index.Value >= range.Start.Value && index.Value < range.End.Value;
}

由于Index覆盖隐式操作符,因此可以传递int型而不是Index结构体。

var range = new Range(1, 10);
var isInRange = range.IsInRangeOf(1); // true, 1..10 is inclusive min range index(1)
var isInRange = range.IsInRangeOf(10); // false, 1..10 exclusive on max range index (10).
var isInRange = range.IsInRangeOf(100); // false

static class ExtensionMethods
{
    internal static bool IsBetween(this double number,double bound1, double bound2)
    {
        return Math.Min(bound1, bound2) <= number && number <= Math.Max(bound2, bound1);
    }

    internal static bool IsBetween(this int number, double bound1, double bound2)
    {
        return Math.Min(bound1, bound2) <= number && number <= Math.Max(bound2, bound1);
    }
}

使用

double numberToBeChecked = 7;

var result = numberToBeChecked.IsBetween(100,122);

var result = 5.IsBetween(100,120);

var result = 8.0.IsBetween(1.2,9.6);

通过一些扩展方法的滥用,我们可以得到以下“优雅”的解决方案:

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!");
        }
    }
}

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

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