可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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".