2

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

Community
  • 1
  • 1
Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
  • Write out the *compilable* code you would want to be executed in your example, when `T1` is `byte`, `T2` is `int`, and so on. Look at that code and consider what hope you have of making it generic. – AakashM May 09 '12 at 08:20
  • Should the extension method not spelled `IsBetween`? Sounds better in my eyes. – Felix K. May 09 '12 at 08:47
  • @FelixK.: Its the code inside Extension Method that sounds better inside my brain. – Nikhil Agrawal May 09 '12 at 08:50
  • Your example *doesn't* show "different datatypes but same base class". It's hard to answer a question when it contradicts itself. – Jon Skeet May 10 '12 at 07:11
  • Seriously, *write out* the method `Between` with *static types* as it would need to exist to satisfy your example that has `byte`, `int`, `double`. Just write it out. *Then* consider how that method that you have written might be made generic. – AakashM May 10 '12 at 08:49

5 Answers5

3

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.

Botz3000
  • 39,020
  • 8
  • 103
  • 127
1

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))
Tigran
  • 61,654
  • 8
  • 86
  • 123
  • I think you missed the point EM. If that is what i wanted to do why will it write Ext.-Met. and more over how will i keep on converting every available datatype. – Nikhil Agrawal May 09 '12 at 08:19
1
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

Tilak
  • 30,108
  • 19
  • 83
  • 131
0

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.'

Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60
  • I think you missed the point EM. If that is what i wanted to do why will it write Ext.-Met. and more over how will i keep on converting every available datatype. – Nikhil Agrawal May 09 '12 at 08:19
0

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".

Raphaël Althaus
  • 59,727
  • 6
  • 96
  • 122