Implémentation d'opérations de comparaison

De Appmethod Topics
Aller à : navigation, rechercher

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.

Par exemple, l'objet TConvertVariantType de l'unité VarConv implémente la méthode Compare suivante :

Object Pascal:

 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é :

Object Pascal :

 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.

Voir aussi