比較演算の実装
クラスを作成してカスタム バリアント型を有効にする への移動
カスタム バリアント型に比較演算子(=, <>, <, <=, >, >=)をサポートさせるには、2 つの方法があります。 Compare
メソッドをオーバーライドするか、CompareOp
メソッドをオーバーライドすることができます。
カスタム バリアント型が比較演算子を完全にサポートしているのであれば、Compare メソッドを使用するのが一番簡単です。 Compare
は、3 つのパラメータをとります: 左側オペランド、右側オペランド、そして、その 2 つの関係を返す var パラメータです。
TConvertVariantType
オブジェクトは、次の Compare
メソッドを実装しています:
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;
カスタム型が、概念「より大きい」または「より小さい」をサポートしておらず、「等しい」または「等しくない」のみの場合、Compare
メソッドの実装は難しくなります。これは、Compare
が crLessThan
、crEqual
、crGreaterThan
を返す必要があるからです。 唯一有効なレスポンスが「等しくない」である場合、返された crLessThan
や crGreaterThan
は認識できなくなります。
このため、順序付けの概念をサポートしない型に対しては、CompareOp メソッドを代わりにオーバーライドすることができます。
CompareOp には 3 つのパラメータ --- 左側オペランドの値、右側オペランドの値、および比較演算子 --- があります。 このメソッドを実装すると、演算を実行し、比較が True
かどうかを示す論理値を返すことができます。 それから、比較が意味をなさない場合には、RaiseInvalidOp メソッドを呼び出します。
CompareOp
メソッドは、System.VarCmplx ユニットで定義される TComplexVariantType
からきています。 等価、不等価のテストのみをサポートします。
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;
これら相方の実装がサポートするオペランドの型が、非常に限定されたものである点に注意してください。 二項演算の実装のように、メソッド RightPromotion
と LeftPromotion
を使用して、強制キャストを行ってから Compare
や CompareOp
を呼び出すと、注意しなければならないケースを減らすことができます。