比較演算の実装

提供: Appmethod Topics
移動先: 案内検索

クラスを作成してカスタム バリアント型を有効にする への移動


カスタム バリアント型に比較演算子(=, <>, <, <=, >, >=)をサポートさせるには、2 つの方法があります。 Compare メソッドをオーバーライドするか、CompareOp メソッドをオーバーライドすることができます。

カスタム バリアント型が比較演算子を完全にサポートしているのであれば、Compare メソッドを使用するのが一番簡単です。 Compare は、3 つのパラメータをとります: 左側オペランド、右側オペランド、そして、その 2 つの関係を返す var パラメータです。

たとえば、VarConv ユニット内の TConvertVariantType オブジェクトは、次の Compare メソッドを実装しています:

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;

カスタム型が、概念「より大きい」または「より小さい」をサポートしておらず、「等しい」または「等しくない」のみの場合、Compare メソッドの実装は難しくなります。これは、ComparecrLessThancrEqualcrGreaterThan を返す必要があるからです。 唯一有効なレスポンスが「等しくない」である場合、返された crLessThancrGreaterThan は認識できなくなります。

このため、順序付けの概念をサポートしない型に対しては、CompareOp メソッドを代わりにオーバーライドすることができます。

CompareOp には 3 つのパラメータ --- 左側オペランドの値、右側オペランドの値、および比較演算子 --- があります。 このメソッドを実装すると、演算を実行し、比較が True かどうかを示す論理値を返すことができます。 それから、比較が意味をなさない場合には、RaiseInvalidOp メソッドを呼び出します。

たとえば、次の CompareOp メソッドは、System.VarCmplx ユニットで定義される TComplexVariantType からきています。 等価、不等価のテストのみをサポートします。

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;

これら相方の実装がサポートするオペランドの型が、非常に限定されたものである点に注意してください。 二項演算の実装のように、メソッド RightPromotionLeftPromotion を使用して、強制キャストを行ってから CompareCompareOp を呼び出すと、注意しなければならないケースを減らすことができます。

関連項目