C # 및 .NET 3.5 / 4로 어떻게 우아하게 수행 할 수 있습니까?
예를 들어, 숫자는 1과 100 사이 일 수 있습니다.
충분하다면 간단하다는 것을 안다. 그러나이 질문의 키워드는 우아합니다. 프로덕션 용이 아닌 장난감 프로젝트 용입니다.
이 질문은 속도가 아니라 코드의 아름다움에 관한 것입니다. 효율성과 그에 대한 이야기를 중단하십시오. 성가대에게 설교한다는 것을 기억하십시오.
if
"바로크"가 아닌 경우 수정하지 마십시오.
C # 및 .NET 3.5 / 4로 어떻게 우아하게 수행 할 수 있습니까?
예를 들어, 숫자는 1과 100 사이 일 수 있습니다.
충분하다면 간단하다는 것을 안다. 그러나이 질문의 키워드는 우아합니다. 프로덕션 용이 아닌 장난감 프로젝트 용입니다.
이 질문은 속도가 아니라 코드의 아름다움에 관한 것입니다. 효율성과 그에 대한 이야기를 중단하십시오. 성가대에게 설교한다는 것을 기억하십시오.
if
"바로크"가 아닌 경우 수정하지 마십시오.
답변:
많은 옵션이 있습니다 :
int x = 30;
if (Enumerable.Range(1,100).Contains(x))
//true
if (x >= 1 && x <= 100)
//true
또한이 SO 게시물 에서 정규식 옵션을 확인하십시오 .
if
진술 보다 더 멋진 것을 원합니다 . 이것은 확실히 그것을 달성합니다 ...;)
당신은 의미합니까?
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);
말하자면, 이것은 수표 자체가 단 한 줄일 때 해야하는 바보 같은 것 같습니다.
다른 사람들이 말했듯이 간단한 if를 사용하십시오.
주문에 대해 생각해야합니다.
예 :
1 <= x && x <= 100
보다 읽기 쉽다
x >= 1 && x <= 100
=
대신 입력 할 때 알려줍니다 ==
. 평등하지 않은 관계 연산자에는 도움이되지 않지만 일관되게 사용하는 것은 쉽습니다.
x
복잡한 함수 호출 또는 시간 소모적 인 Linq- 표현을 고려하십시오 . 이 경우 좋은 일이 아닌 두 번 수행합니다. 물론 값을 임시 로컬 변수에 저장해야하지만 다른 if 또는 else-if가 실패한 후에 만 함수를 호출하려는 경우가 있습니다 (예 : else-if-statements). 임시 변수를 사용하면 어쨌든 변수를 호출해야합니다. 이러한 경우 확장 방법 (다른 답변에서 언급)이 가장 좋은 해결책입니다.
프로덕션 코드에서는 간단히 작성합니다.
1 <= x && x <= 100
이해하기 쉽고 읽기 쉽습니다.
다음은 약간의 수학을 사용하여 비교 횟수를 2에서 1로 줄이는 영리한 방법입니다. 아이디어는 숫자가 범위를 벗어나면 두 요인 중 하나가 음수가되고 숫자가 경계 중 하나와 같으면 0이되는 것입니다.
범위가 포함 된 경우 :
(x - 1) * (100 - x) >= 0
또는
(x - min) * (max - x) >= 0
범위가 독점적 인 경우 :
(x - 1) * (100 - x) > 0
또는
(x - min) * (max - x) > 0
1 < x && x < 100
생산 코드를 사용하려고 합니다. 이해하기 쉽습니다.
1 < x & x < 100
(&& short circuit 없음) 컴파일러에게 x < 100
결과에 상관없이 항상 평가할 수 있도록 지시합니다 1 < x
. 이상하게도 (분기 예측으로 인해) 때로는이 간단한 작업을 건너 뛰는 것보다 항상이 간단한 작업을 수행하는 것이 더 빠릅니다.
나는 이것을 제안한다 :
public static bool IsWithin<T>(this T value, T minimum, T maximum) where T : IComparable<T> {
if (value.CompareTo(minimum) < 0)
return false;
if (value.CompareTo(maximum) > 0)
return false;
return true;
}
예 :
45.IsWithin(32, 89)
true
87.2.IsWithin(87.1, 87.15)
false
87.2.IsWithin(87.1, 87.25)
true
물론 변수가있는 경우 :
myvalue.IsWithin(min, max)
읽기 쉽고 (인간의 언어에 가깝다) 모든 비교 가능한 유형 (정수, 이중, 사용자 정의 유형 ...)과 함께 작동합니다.
개발자가 코드를 이해하기 위해 "브레인 사이클"을 낭비하지 않기 때문에 코드를 읽기 쉽게하는 것이 중요합니다. 코딩 세션이 길어지면 뇌주기가 낭비되어 개발자가 더 빨리 피곤해지고 버그가 발생하기 쉽습니다.
IsInRange. I'm not that keen on Ben's inclusive boolean as that requires a few more brain cycles. It has the advantage that it can be used in any class that that implements IComparer. This is in my Extensions now along with
LiesWithin / LiesInside. Just can't decide which.
NotOutside 라는 이름을 변경 했지만 부정적인 조건을 좋아하지 않습니다
약간의 확장 방법 남용으로 다음과 같은 "우아한"솔루션을 얻을 수 있습니다.
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!");
}
}
}
enum Inclusive
값 : Lower
, Upper
, All
. 그리고 통할 In
유형의 기능을 하나 추가 매개 변수 enum Inclusive
의 기본 값을 Inclusive.All
업데이트 To
핸들 함수 본문을 All
, Lower
, Upper
값 :
이것이 부수적 인 경우 간단한 if
합니다. 여러 곳에서 이런 일이 발생하면 다음 두 가지를 고려할 수 있습니다.
다음과 같은 것 :
[Between("parameter", 0, 100)]
public void Foo(int parameter)
{
}
&&
표현식을 사용하여 두 비교를 결합하는 것이 가장 우아한 방법입니다. 멋진 확장 방법 등을 사용하려고하면 상한, 하한 또는 둘 다를 포함할지에 대한 문제가 발생합니다. 추가 변수를 추가하거나 포함 이름을 나타 내기 위해 확장명을 변경하면 코드가 길어지고 읽기 어려워집니다 (대부분의 프로그래머에게). 또한 비교가 적절하지 않으면 Resharper와 같은 도구가 경고합니다 (number > 100 && number < 1
) 이 방법을 사용하면 ( 'i.IsBetween (100, 1)') 사용하지 않습니다.
내가 유일하게 할 말은 예외를 던질 의도로 입력을 검사하는 경우 코드 계약 사용을 고려해야한다는 것입니다.
Contract.Requires(number > 1 && number < 100)
이것은보다 우아하며 if(...) throw new Exception(...)
, 누군가 숫자가 먼저 범위 내에 있는지 확인하지 않고 메소드를 호출하려고하면 컴파일 타임 경고를받을 수 있습니다.
간단한 경우보다 더 많은 코드를 작성하려면 다음을 수행하십시오. 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());
추가:실제로 코드베이스에서 "평등을 검사하는 것"(또는 <,>)을 거의 사용하지 않는다는 점은 주목할 가치가 있습니다. (가장 사소한 상황이 아닌 경우) 순수한 예를 들어, 모든 게임 프로그래머는 모든 프로젝트에서 다음과 같은 범주를 기본 사항으로 사용합니다. 이 예제에서는 해당 환경에 내장 된 함수 (대략)를 사용합니다. 실제로는 일반적으로 엔지니어링중인 상황 유형에 따라 실수의 컴퓨터 표현에 대한 비교의 의미에 대한 자체 개념을 신중하게 개발해야합니다. (아마도 컨트롤러, PID 컨트롤러 등과 같은 작업을 수행하는 경우 전체 문제가 핵심적이고 매우 어려워 프로젝트의 본질이된다는 것을 언급조차하지 마십시오.
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;
}
return (value >= Min && value <= Max);
다른 모든 대답은 나에 의해 발명되지 않았기 때문에 여기에 내 구현 만 있습니다.
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);
편집 : 새로운 답변 제공. 이 질문에 대한 첫 번째 답변을 썼을 때 C #을 사용하기 시작했으며, 이제 "솔루션"이 순진하고 비효율적이라는 것을 알게되었습니다.
내 원래 답변 : 더 간단한 버전으로 갈 것입니다.
if(Enumerable.Range(1,100).Contains(intInQuestion)) { ...DoStuff; }
더 효율적인 다른 솔루션을 보지 못했기 때문에 (적어도 내 테스트에 따르면) 다른 해결책을 제시 할 것입니다.
음수 범위에서도 작동 하는 새롭고 더 나은 방법 :
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
양수 범위와 음수 범위를 모두 사용할 수 있으며 기본값은
1..100 (포함) 및 사용 x
수 등은에 의해 정의 된 임의의 범위가 다음에 확인하는 min
하고 max
.
예 1 :
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
Console.WriteLine(inRange(25));
Console.WriteLine(inRange(1));
Console.WriteLine(inRange(100));
Console.WriteLine(inRange(25, 30, 150));
Console.WriteLine(inRange(-25, -50, 0));
보고:
True
True
True
False
True
예 2 : 1에서 150 사이의 임의의 정수 목록 사용
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
// Generate 100000 ints between 1 and 150
var intsToCheck = new List<int>();
var randGen = new Random();
for(int i = 0; i < 100000; ++i){
intsToCheck.Add(randGen.Next(150) + 1);
}
var counter = 0;
foreach(int n in intsToCheck) {
if(inRange(n)) ++counter;
}
Console.WriteLine("{0} ints found in range 1..100", counter);
보고:
66660 ints found in range 1..100
실행 시간 : 0.016 초
오래된 마음에 드는 새로운 트위스트 :
public bool IsWithinRange(int number, int topOfRange, int bottomOfRange, bool includeBoundaries) {
if (includeBoundaries)
return number <= topOfRange && number >= bottomOfRange;
return number < topOfRange && number > bottomOfRange;
}
C에서 시간 효율성이 중요하고 정수 오버플로가 줄어든다면 할 수 if ((unsigned)(value-min) <= (max-min)) ...
있습니다. 'max'및 'min'이 독립 변수 인 경우 (max-min)에 대한 추가 빼기는 시간을 낭비하지만 컴파일 시간에 해당 표현식을 사전 계산할 수 있거나 런타임시 한 번 계산하여 많은 수를 테스트 할 수있는 경우 동일한 범위에 해당하는 숫자 인 경우, 값이 범위 내에있는 경우에도 위의 표현식을 효율적으로 계산할 수 있습니다 (값의 큰 부분이 유효한 범위 아래에 있으면 값이 빠른 경우 종료if ((value >= min) && (value <= max)) ...
되므로 사용하는 것이 더 빠를 수 있습니다) 최소 미만입니다).
그러나 그러한 구현을 사용하기 전에 대상 시스템을 벤치마킹하십시오. 일부 프로세서에서는 두 부분의 표현이 모든 경우에 더 빠를 수 있습니다. 두 비교는 독립적으로 수행 될 수있는 반면 빼기 및 비교 방법에서는 비교가 실행되기 전에 빼기가 완료되어야합니다.
이런 건 어때?
if (theNumber.isBetween(low, high, IntEx.Bounds.INCLUSIVE_INCLUSIVE))
{
}
다음과 같은 확장 방법으로 (테스트) :
public static class IntEx
{
public enum Bounds
{
INCLUSIVE_INCLUSIVE,
INCLUSIVE_EXCLUSIVE,
EXCLUSIVE_INCLUSIVE,
EXCLUSIVE_EXCLUSIVE
}
public static bool isBetween(this int theNumber, int low, int high, Bounds boundDef)
{
bool result;
switch (boundDef)
{
case Bounds.INCLUSIVE_INCLUSIVE:
result = ((low <= theNumber) && (theNumber <= high));
break;
case Bounds.INCLUSIVE_EXCLUSIVE:
result = ((low <= theNumber) && (theNumber < high));
break;
case Bounds.EXCLUSIVE_INCLUSIVE:
result = ((low < theNumber) && (theNumber <= high));
break;
case Bounds.EXCLUSIVE_EXCLUSIVE:
result = ((low < theNumber) && (theNumber < high));
break;
default:
throw new System.ArgumentException("Invalid boundary definition argument");
}
return result;
}
}
다음과 같이 Range 개체를 수행합니다.
public class Range<T> where T : IComparable
{
public T InferiorBoundary{get;private set;}
public T SuperiorBoundary{get;private set;}
public Range(T inferiorBoundary, T superiorBoundary)
{
InferiorBoundary = inferiorBoundary;
SuperiorBoundary = superiorBoundary;
}
public bool IsWithinBoundaries(T value){
return InferiorBoundary.CompareTo(value) > 0 && SuperiorBoundary.CompareTo(value) < 0;
}
}
그런 다음이 방법을 사용하십시오.
Range<int> myRange = new Range<int>(1,999);
bool isWithinRange = myRange.IsWithinBoundaries(3);
그렇게하면 다른 유형에 재사용 할 수 있습니다.
Range
개체는 사용할 필요 CompareTo
항목이 아닌 비교하는 방법을 <
연산자.
IComparable
오버로드하지 않고 구현하는 것이 전적으로 합리적입니다 <
.
"숫자"가 범위 내에 있는지 확인할 때 의미가 무엇인지 명확해야하며 두 숫자가 같은 의미는 무엇입니까? 일반적으로 모든 엡실론 볼에 모든 부동 소수점 숫자를 래핑해야합니다.이 값은 작은 값을 선택하고 두 값이 가까운 경우 동일한 것입니다.
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);
이 두 헬퍼를 배치하고 필요한 수를 두 배로 캐스팅 할 수 있다고 가정합니다. 열거 형과 다른 방법 만 있으면됩니다.
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");
}
}
이제 이것은 원하는 것보다 훨씬 많을 수 있지만 항상 반올림을 처리하고 값이 반올림되었는지 여부와 장소를 기억하려고하지 않습니다. 필요한 경우 엡실론에서 작동하고 엡실론을 변경할 수 있도록 이것을 쉽게 확장 할 수 있습니다.
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 결과 = 5. IsBetween (100,120);
var 결과 = 8.0. IsBetween (1.2,9.6);
허용 된 답변에 대한 @Daap의 의견에 관심이 있고 값을 한 번만 전달할 수있는 경우 다음 중 하나를 시도 할 수 있습니다
bool TestRangeDistance (int numberToCheck, int bottom, int distance)
{
return (numberToCheck >= bottom && numberToCheck <= bottom+distance);
}
//var t = TestRangeDistance(10, somelist.Count()-5, 10);
또는
bool TestRangeMargin (int numberToCheck, int target, int margin)
{
return (numberToCheck >= target-margin && numberToCheck <= target+margin);
}
//var t = TestRangeMargin(10, somelist.Count(), 5);
나는 경계가 전환 될 수있는 곳을 수행하는 우아한 방법을 찾고있었습니다 (즉, 값이 어떤 순서인지 확실하지 않음).
이것은? :가 존재하는 최신 버전의 C #에서만 작동합니다.
bool ValueWithinBounds(float val, float bounds1, float bounds2)
{
return bounds1 >= bounds2 ?
val <= bounds1 && val >= bounds2 :
val <= bounds2 && val >= bounds1;
}
분명히 목적에 따라 = 기호를 변경할 수 있습니다. 타입 캐스팅으로도 화려할 수 있습니다. 방금 범위 내에서 float 반환이 필요했습니다.
두 경계 값 중 어느 것이 먼저 큰지 결정할 필요가 없기 때문에 우아합니다. 또한 가지가 없습니다.
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);
}
이것들은 도움이 될 수있는 확장 방법입니다.
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;
}
메소드 매개 변수의 유효성을 검사하는 경우 어떤 솔루션도 ArgumentOutOfRangeException을 발생시키지 않으며 포괄적 / 배타적 최소 / 최대 값을 쉽고 적절하게 구성 할 수 없습니다.
이런 식으로 사용
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);
찾고있는 in [1..100]
? 파스칼뿐입니다.
when (number) { in 0..9 -> println("1 digit") in 10..99 -> println("2 digits") in 100..999 -> println("3 digits") }