Implémentation d'opérations de comparaison
Remonter à Création d'une classe pour le type variant personnalisé
Il y a deux façons de permettre à un type variant personnalisé de supporter les opérateurs de comparaison (=, <>, <, <=, >, >=). Vous pouvez redéfinir la méthode Compare
ou la méthode CompareOp
.
La méthode Compare est la plus simple si votre type variant personnalisé supporte la totalité des opérateurs de comparaison. Compare
prend trois paramètres : l'opérande gauche, l'opérande droit et un paramètre var qui renvoie la relation entre les deux.
TConvertVariantType
de l'unité VarConv implémente la méthode Compare
suivante :
Delphi:
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;
Si le type personnalisé ne supporte pas le concept de "supérieur à" ou "inférieur à" et seulement "égal à" ou "différent de", il est difficile d'implémenter la méthode Compare
, car Compare
doit renvoyer crLessThan
, crEqual
ou crGreaterThan
. Quand la seule réponse correcte est "différent de", il est impossible de savoir s'il faut renvoyer crLessThan
ou crGreaterThan
.
Donc, pour les types qui ne supportent pas le concept d'ordre, vous pouvez à la place redéfinir la méthode CompareOp.
CompareOp a trois paramètres : la valeur de l'opérande gauche, la valeur de l'opérande droit et l'opérateur de comparaison. Implémentez cette méthode pour effectuer l'opération et renvoyer un booléen qui indique si la comparaison est True
. Vous pouvez alors appeler la méthode RaiseInvalidOp quand la comparaison n'a aucun sens.
Par exemple, la méthode CompareOp
suivante vient de l'objet TComplexVariantType
de l'unité System.VarCmplx. Elle ne supporte qu'un test d'égalité ou d'inégalité :
Delphi :
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;
Remarquez que les types d'opérandes qui supportent ces deux implémentations sont très limités. Comme avec les opérations binaires, vous pouvez utiliser les méthodes RightPromotion
et LeftPromotion
pour limiter les cas à considérer, en forçant un transtypage avant que Compare
ou CompareOp
ne soit appelée.