Generics and operators...

Upon discovering generics, I seem to be able to get 99% of a solution, but the last 1% is killing me.

Say you want to make a generic class to compare two numbers for whatever condition the user specifies...(in red)... and then return a boolean to indicate whether the first argument was related to the second argument in the chosen way

LessThan

GreaterThan

GreaterThanOrEqual

Equal

Etc...

 

Im sorry about the horrifyingly bad formatting of code in here, but i've tried everything in this stupid window to get the paragraph spacing to single space when hitting return, but for some reason it refuses to do so. 

Anyway, since you cannot constrain a generic class to only accept Int32, Double, etc because those cannot be inherited from, and you cannot know what format the arguments are going to come to you in...

    int, double

    double, double

    double, int

    single, double

...etc, you might make a generic class that accepts 2 generic types... like so

Public Class TestGeneric(Of U, V)

and that way you can hold a variable of one type (say an Int32) and another variable of a different type, (say a Double) and do your magic comparing them in some function.  Well, I wrote a class to do this and below in the function IsDataValid is where the problem arises that I cannot figure out.

 

Public Enum XRelatesToY

    X_Equals_Y

    X_IsGreaterThanOrEqual_Y

    X_IsGreaterThan_Y

    X_IsLessThan_Y

    X_IsLessThanOrEqual_Y

End Enum

 

 

Public Class XRelatesToY(Of TypeX, TypeY)

   Inherits RuleBase 

    Private _X As TypeX

    Private _Y As TypeY

    Private _XRelatesToY As XRelatesToY

 

Public Property X() As TypeX

Get

Return _X

End Get

Set(ByVal value As TypeX)

_X = value

End Set

End Property

 

Public Property Y() As TypeY

Get

Return _Y

End Get

Set(ByVal value As TypeY)

_Y = value

End Set

End Property

 

Public Property Relation() As XRelatesToY

Get

Return _XRelatesToY

End Get

Set(ByVal value As XRelatesToY)

_XRelatesToY = value

End Set

End Property

 

 

Public Overrides Function IsDataValid() As Boolean

  Select Case _XRelatesToY

      Case XRelatesToY.X_Equals_Y

              If _X <> _Y Then Return False Else Return True

      Case XRelatesToY.X_IsGreaterThan_Y

      Case XRelatesToY.X_IsGreaterThanOrEqual_Y

      Case XRelatesToY.X_IsLessThan_Y

      Case XRelatesToY.X_IsLessThanOrEqual_Y

  End Select

End Function

End Class

 

The error message you will get here is "Operator is not defined for types _X and _Y"  and even though you only intend on ever passing Int32, Double, etc which DO have those operators defined on them, this refuses to work.

So the bottom line is, how do I write a generic class that will take any two numeric types as arguments to a function, where it then compares those types for ">" or "<" or "=" etc and returns a boolean based on the type of comparison you wanted between X and Y.  If you instantiate the class and choose "X_IsGreaterThan_Y" then you expect your class to accept two generic types and compare them on that basis and return a true or false.

 




Answer this question

Generics and operators...

  • AmyHa

    Hi, I'm not sure of what you're trying to do, but comparisons only work on objects of the same type. The vb compiler hides this by handling conversions to a common type so comparisons can be done, so if you have:

    if 1 < 1.0 then...

    Behind the scenes, the compiler selects a common type to which both arguments can be converted (double in this case), casts both arguments to it and then compares the values. Your class would have to do something similar.

    Maybe you could tell us why do you need to write such a method to compare two different types, and then we might be able to help you some more.



  • Ramachandran V

    I am making a set of business rule classes that work against a datatable, and one of the rule classes is comparing the value of one field against another with some relationship in mind. I work for the Assessors office (property taxes). This isn't the greatest example, but for arguments sake, say for instance we have a datatable that has a column defined as a double, and another column defined as an int, and the first column holds the square footage of the first floor, while the second holds the square footage of the 2nd floor.

    Well, most houses don't have more square feet on their second floor than their first unless they have a REALLY odd shaped house. So you might apply a rule that says Column1 must be greater than Column2 for any row in the datatable... well I don't want to get off on the architecture of business rules, I just want to know how to take 2 numeric values that may be any numeric type and compare them and return a boolean result indicating whether the rule was satisifed or not.



  • Dave Neigler

    What I'd do in this case, would be in your method to cast both X and Y to double, and compare that - you may have to cast down to object first:

    if cdbl(cobj(X)) < cdbl(cobj(Y)) then ...

    This has the problem that you will lose some precision if both types were not double. A double cannot always represent perfectly all the digits of a decimal, for example.

    Basically, if you want better results at some point some code will have to deal with the fact that you're trying to perform an operation between two different types. You can manually write the code for all combinations of types (code that determines a cast type from the types of the two arguments to the comparison, then casts each argument to that type, then performs the comparison), but unless you really need the precision, I'd go with the above solution.

    The other comment is that in some cases, even increasing the precision might not return the expected results - whenever working with floating point values, remember that a particular decimal value may not have a perfect representation in a double variable - comparisons should be made against intervals around an expected value.

    I think this is one of those little things that seem simple but hide some complexity - sorry :)



  • Generics and operators...