我如何用c#优雅地做到这一点?
例如,一个数字可以是1到100之间。
我知道一个简单的if (x >= 1 && x <= 100)就足够了;但是有很多语法糖和新特性不断添加到c# /。Net这个问题是关于更习惯的(一个可以称之为优雅的)写法。
性能不是问题,但请在非O(1)的解决方案中添加性能说明,因为人们可能会复制粘贴建议。
我如何用c#优雅地做到这一点?
例如,一个数字可以是1到100之间。
我知道一个简单的if (x >= 1 && x <= 100)就足够了;但是有很多语法糖和新特性不断添加到c# /。Net这个问题是关于更习惯的(一个可以称之为优雅的)写法。
性能不是问题,但请在非O(1)的解决方案中添加性能说明,因为人们可能会复制粘贴建议。
当前回答
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);
其他回答
我正在寻找一种优雅的方式来做它的边界可能被切换(即。不确定值的顺序)。
这只适用于存在?:的新版本的c#
bool ValueWithinBounds(float val, float bounds1, float bounds2)
{
return bounds1 >= bounds2 ?
val <= bounds1 && val >= bounds2 :
val <= bounds2 && val >= bounds1;
}
显然,您可以根据自己的需要更改=号。也可以用类型转换。我只需要在边界内(或等于)返回一个浮点数
如果是为了验证方法参数,没有一个解决方案会抛出argumentoutofranceexception,并允许简单/适当地配置包含/排除的最小/最大值。
像这样使用
public void Start(int pos)
{
pos.CheckRange(nameof(pos), min: 0);
if (pos.IsInRange(max: 100, maxInclusive: false))
{
// ...
}
}
我只是写出了这些漂亮的函数。它还具有对有效值没有分支(单个if)的优点。最难的部分是制作适当的异常消息。
/// <summary>
/// Returns whether specified value is in valid range.
/// </summary>
/// <typeparam name="T">The type of data to validate.</typeparam>
/// <param name="value">The value to validate.</param>
/// <param name="min">The minimum valid value.</param>
/// <param name="minInclusive">Whether the minimum value is valid.</param>
/// <param name="max">The maximum valid value.</param>
/// <param name="maxInclusive">Whether the maximum value is valid.</param>
/// <returns>Whether the value is within range.</returns>
public static bool IsInRange<T>(this T value, T? min = null, bool minInclusive = true, T? max = null, bool maxInclusive = true)
where T : struct, IComparable<T>
{
var minValid = min == null || (minInclusive && value.CompareTo(min.Value) >= 0) || (!minInclusive && value.CompareTo(min.Value) > 0);
var maxValid = max == null || (maxInclusive && value.CompareTo(max.Value) <= 0) || (!maxInclusive && value.CompareTo(max.Value) < 0);
return minValid && maxValid;
}
/// <summary>
/// Validates whether specified value is in valid range, and throws an exception if out of range.
/// </summary>
/// <typeparam name="T">The type of data to validate.</typeparam>
/// <param name="value">The value to validate.</param>
/// <param name="name">The name of the parameter.</param>
/// <param name="min">The minimum valid value.</param>
/// <param name="minInclusive">Whether the minimum value is valid.</param>
/// <param name="max">The maximum valid value.</param>
/// <param name="maxInclusive">Whether the maximum value is valid.</param>
/// <returns>The value if valid.</returns>
public static T CheckRange<T>(this T value, string name, T? min = null, bool minInclusive = true, T? max = null, bool maxInclusive = true)
where T : struct, IComparable<T>
{
if (!value.IsInRange(min, minInclusive, max, maxInclusive))
{
if (min.HasValue && minInclusive && max.HasValue && maxInclusive)
{
var message = "{0} must be between {1} and {2}.";
throw new ArgumentOutOfRangeException(name, value, message.FormatInvariant(name, min, max));
}
else
{
var messageMin = min.HasValue ? GetOpText(true, minInclusive).FormatInvariant(min) : null;
var messageMax = max.HasValue ? GetOpText(false, maxInclusive).FormatInvariant(max) : null;
var message = (messageMin != null && messageMax != null) ?
"{0} must be {1} and {2}." :
"{0} must be {1}.";
throw new ArgumentOutOfRangeException(name, value, message.FormatInvariant(name, messageMin ?? messageMax, messageMax));
}
}
return value;
}
private static string GetOpText(bool greaterThan, bool inclusive)
{
return (greaterThan && inclusive) ? "greater than or equal to {0}" :
greaterThan ? "greater than {0}" :
inclusive ? "less than or equal to {0}" :
"less than {0}";
}
public static string FormatInvariant(this string format, params object?[] args) => string.Format(CultureInfo.InvariantCulture, format, args);
使用内置的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
如果你想写更多的代码而不是简单的If,也许你可以: 创建一个名为IsBetween的扩展方法
public static class NumberExtensionMethods
{
public static bool IsBetween(this long value, long Min, long Max)
{
// return (value >= Min && value <= Max);
if (value >= Min && value <= Max) return true;
else return false;
}
}
...
// Checks if this number is between 1 and 100.
long MyNumber = 99;
MessageBox.Show(MyNumber.IsBetween(1, 100).ToString());
Addendum: it's worth noting that in practice you very rarely "just check for equality" (or <, >) in a codebase. (Other than in the most trivial situations.) Purely as an example, any game programmer would use categories something like the following in every project, as a basic matter. Note that in this example it (happens to be) using a function (Mathf.Approximately) which is built in to that environment; in practice you typically have to carefully develop your own concepts of what comparisons means for computer representations of real numbers, for the type of situation you are engineering. (Don't even mention that if you're doing something like, perhaps a controller, a PID controller or the like, the whole issue becomes central and very difficult, it becomes the nature of the project.) BY no means is the OP question here a trivial or unimportant question.
private bool FloatLessThan(float a, float b)
{
if ( Mathf.Approximately(a,b) ) return false;
if (a<b) return true;
return false;
}
private bool FloatLessThanZero(float a)
{
if ( Mathf.Approximately(a,0f) ) return false;
if (a<0f) return true;
return false;
}
private bool FloatLessThanOrEqualToZero(float a)
{
if ( Mathf.Approximately(a,0f) ) return true;
if (a<0f) return true;
return false;
}
我使用下一个“优雅”的解决方案:
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
}