Implementing Comparison Operations
There are two ways to enable a custom variant type to support comparison operators (=, <>, <, <=, >, >=). You can either override the
Compare method, or you can override the
The Compare method is easier if your custom variant type supports the full range of comparison operators.
Compare takes three parameters: the left-hand operand, the right-hand operand, and a var Parameter that returns the relationship between the two.
TConvertVariantTypeobject in the VarConv unit implements the following
procedure TConvertVariantType.Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); const CRelationshipToRelationship: array [TValueRelationship] of TVarCompareResult = (crLessThan, crEqual, crGreaterThan); var LValue: Double; LType: TConvType; LRelationship: TValueRelationship; begin // supports... // convvar cmp number // Compare the value of convvar and the given number // convvar1 cmp convvar2 // Compare after converting convvar2 to convvar1's unit type // The right can also be a string. If the string has unit info then it is // treated like a varConvert else it is treated as a double LRelationship := EqualsValue; case Right.VType of varString: if TryStrToConvUnit(Variant(Right), LValue, LType) then if LType = CIllegalConvType then LRelationship := CompareValue(TConvertVarData(Left).VValue, LValue) else LRelationship := ConvUnitCompareValue(TConvertVarData(Left).VValue, TConvertVarData(Left).VConvType, LValue, LType) else RaiseCastError; varDouble: LRelationship := CompareValue(TConvertVarData(Left).VValue, TVarData(Right).VDouble); else if Left.VType = VarType then LRelationship := ConvUnitCompareValue(TConvertVarData(Left).VValue, TConvertVarData(Left).VConvType, TConvertVarData(Right).VValue, TConvertVarData(Right).VConvType) else RaiseInvalidOp; end; Relationship := CRelationshipToRelationship[LRelationship]; end;
If the custom type does not support the concept of "greater than" or "less than," only "equal" or "not equal," it is difficult to implement the
Compare method, because
Compare must return
crGreaterThan. When the only valid response is "not equal," it is impossible to know whether to return
Thus, for types that do not support the concept of ordering, you can override the CompareOp method instead.
CompareOp has three parameters: the value of the left-hand operand, the value of the right-hand operand, and the comparison operator. Implement this method to perform the operation and return a boolean that indicates whether the comparison is
True. You can then call the RaiseInvalidOp method when the comparison makes no sense.
For example, the following
CompareOp method comes from the
TComplexVariantType object in the System.VarCmplx unit. It supports only a test of equality or inequality:
function TComplexVariantType.CompareOp(const Left, Right: TVarData; const Operator: Integer): Boolean; begin Result := False; if (Left.VType = VarType) and (Right.VType = VarType) then case Operator of opCmpEQ: Result := TComplexVarData(Left).VComplex.Equal(TComplexVarData(Right).VComplex); opCmpNE: Result := not TComplexVarData(Left).VComplex.Equal(TComplexVarData(Right).VComplex); else RaiseInvalidOp; end else RaiseInvalidOp; end;
Note that the types of operands that both these implementations support are very limited. As with Implementing Binary Operations, you can use the
LeftPromotion methods to limit the cases you must consider by forcing a cast before
CompareOp is called.