我如何用c#优雅地做到这一点?
例如,一个数字可以是1到100之间。
我知道一个简单的if (x >= 1 && x <= 100)就足够了;但是有很多语法糖和新特性不断添加到c# /。Net这个问题是关于更习惯的(一个可以称之为优雅的)写法。
性能不是问题,但请在非O(1)的解决方案中添加性能说明,因为人们可能会复制粘贴建议。
我如何用c#优雅地做到这一点?
例如,一个数字可以是1到100之间。
我知道一个简单的if (x >= 1 && x <= 100)就足够了;但是有很多语法糖和新特性不断添加到c# /。Net这个问题是关于更习惯的(一个可以称之为优雅的)写法。
性能不是问题,但请在非O(1)的解决方案中添加性能说明,因为人们可能会复制粘贴建议。
当前回答
Using an && expression to join two comparisons is simply the most elegant way to do this. If you try using fancy extension methods and such, you run into the question of whether to include the upper bound, the lower bound, or both. Once you start adding additional variables or changing the extension names to indicate what is included, your code becomes longer and harder to read (for the vast majority of programmers). Furthermore, tools like Resharper will warn you if your comparison doesn't make sense (number > 100 && number < 1), which they won't do if you use a method ('i.IsBetween(100, 1)').
我要做的唯一另一个评论是,如果你检查输入的意图是抛出异常,你应该考虑使用代码契约:
Contract.Requires(number > 1 && number < 100)
这比if(…)抛出new Exception(…)更优雅,如果有人试图调用您的方法而没有首先确保该数字在边界内,您甚至可以得到编译时警告。
其他回答
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);
有很多选择:
int x = 30;
if (Enumerable.Range(1,100).Contains(x)) //true
实际上,基本的,如果更优雅的话,可以在第一张支票中用倒序写:
if (1 <= x && x <= 100) //true
此外,查看这篇SO帖子的正则表达式选项。
注:
LINQ solution is strictly for style points - since Contains iterates over all items its complexity is O(range_size) and not O(1) normally expected from a range check. More generic version for other ranges (notice that second argument is count, not end): if (Enumerable.Range(start, end - start + 1).Contains(x) There is temptation to write if solution without && like 1 <= x <= 100 - that look really elegant, but in C# leads to a syntax error "Operator '<=' cannot be applied to operands of type 'bool' and 'int'"
因为所有其他答案都不是我发明的,这里只是我的实现:
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);
我不知道,但我用这个方法:
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);
}
在c#中,关于速度和代码原的最佳解决方案,只有一次比较,没有约束检查,并且不会因溢出而容易出错:
public static bool IsInRange(int value, int min, int max) => (uint)(value - min) <= (uint)(max - min);
最小值和最大值包括在内。