Creating Between Extension Method checking value b

2019-07-16 17:52发布

问题:

I have a variable whose value is populated at runtime. I want to check whether that value is between two different datatype values (say lowest and highest) or not using an Extension Method.

These two values (lowest and highest) can be of same datatypes (No problem). Then its like

public static bool Between<T>(this T actual, T lower, T upper) 
    where T : IComparable<T>
{
    return actual.CompareTo(lower) >= 0 && actual.CompareTo(upper) <= 0;
}

courtesy my earlier asked question How to create a Between Extension Method

But what if they have different datatypes but same base class.

say

I want to check like

byte a = 2; //here static but is can be changed at runtime

if(a.Between(0,8.0))
   DoSomething();
else
   DoNothing();

In the above snippet i am checking a byte value between an int value and double value. How to do in such cases. I want to create an extension method like

public static bool Between<T1, T2, T3>(this T1 actual, T2 lowest, T3 highest) 
     where T1: ???? 
     where T2: ????
     where T3: ????
{
     What code to write here???? 
}

For above snippet my EM should return true

回答1:

Just tried it, and the closest i got was this:

public static bool Between<T1, T2, T3>(this T1 actual, T2 lowest, T3 highest) 
     where T1: IComparable 
     where T2: IConvertible
     where T3: IConvertible
{
     return actual.CompareTo(lowest.ToType(typeof(T1), null)) >= 0 && 
            actual.CompareTo(highest.ToType(typeof(T1), null)) <= 0;
}

This will convert T2 and T3 to T1, and then compare them. If the conversion of lowest or highest to the type of T1 fails, you will get an exception (for example if T1 is byte and lower or highest are larger than 255). So you might want to check T1, and if required convert actual to a larger datatype.



回答2:

If you are operating over numeric types, which are first class citizens in CLR, you can not have contract/interface applied to them , naturally. What comes to my mind, is to bring all of them to bigger common numeric type and compare after, say (pseudocode):

public static bool Between(this byte actual, decimal lowest)   
{
    ...
}

and after use it like:

if(a.Between(0,(decimal)8.0))


回答3:

public static bool Between<T1, T2, T3>(this T1 actual, T2 lowest, T3 highest) 
 where T1: T,  IComparable<T> 
 where T2: T
 where T3: T>
{
 return actual.CompareTo(lower) >= 0 && actual.CompareTo(upper) <= 0;
}

IComparable is required only on T1, as only actual (instance of T1) is invoking CompareTo.

Check base class constraint: -> http://msdn.microsoft.com/en-us/library/d5x73970.aspx



回答4:

IComparable requires that the Type being compared is the same Type as the Type being compared to. Therefore you will need to have the same Type as actual, lowest and highest.

That means doing something like this:

byte a = 2;
decimal toCompare = (decimal)a;

if(toCompare.Between(0.0, 8.0))
{
   DoSomething();
}
else
{
   DoNothing();
}

If you try and compare across types, you will get an exception at runtime.

Console.WriteLine(1.CompareTo(2.0));

will result in an exception being thrown with the message 'Object must be of type Int32.'



回答5:

Not that elegant, but I would do a specific method for numeric comparison

 public static bool BetweenNumeric<T1, T2, T3>(this T1 actual, T2 lowest, T3 highest)
            where T1 : IConvertible
            where T2 : IConvertible
            where T3 : IConvertible
        {
            try
            {
                var actualDouble = Convert.ToDouble(actual);
                var lowestDouble = Convert.ToDouble(lowest);
                var highestDouble = Convert.ToDouble(highest);
                return (actualDouble).CompareTo(lowestDouble) >= 0 && actualDouble.CompareTo(highestDouble) <= 0;
            }
            catch
            {
                return false;
            }
        }

by the way, if one of the type is a boolean, for example, it will be converted to 1.0... instead of being catched.

Not perfect, but you'll avoid tons of "type checks".