Delphi 中,对 Variant 类型进行了增强,支持了自己的 UnicodeString 、 AnsiString 和 TBcd,那么有人可能奇怪它是怎么完成这一支持的呢?秘密就在 TCustomVariantType 这个类型。
我们看 Variants 单元对其定义:
TCustomVariantType = class(TObject, IInterface) private FVarType: TVarType; protected { IInterface } function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; procedure SimplisticClear(var V: TVarData); procedure SimplisticCopy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean = False); procedure RaiseInvalidOp; procedure RaiseCastError; procedure RaiseDispError; function LeftPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean; virtual; function RightPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean; virtual; function OlePromotion(const V: TVarData; out RequiredVarType: TVarType): Boolean; virtual; procedure DispInvoke(Dest: PVarData; [Ref] const Source: TVarData; CallDesc: PCallDesc; Params: Pointer); virtual; procedure VarDataInit(var Dest: TVarData); procedure VarDataClear(var Dest: TVarData); procedure VarDataCopy(var Dest: TVarData; const Source: TVarData); procedure VarDataCopyNoInd(var Dest: TVarData; const Source: TVarData); procedure VarDataCast(var Dest: TVarData; const Source: TVarData); procedure VarDataCastTo(var Dest: TVarData; const Source: TVarData; const AVarType: TVarType); overload; procedure VarDataCastTo(var Dest: TVarData; const AVarType: TVarType); overload; procedure VarDataCastToOleStr(var Dest: TVarData); procedure VarDataFromStr(var V: TVarData; const Value: string); {$IFNDEF NEXTGEN} procedure VarDataFromOleStr(var V: TVarData; const Value: WideString); procedure VarDataFromLStr(var V: TVarData; const Value: AnsiString); {$ENDIF !NEXTGEN} function VarDataToStr(const V: TVarData): string; function VarDataIsEmptyParam(const V: TVarData): Boolean; function VarDataIsByRef(const V: TVarData): Boolean; function VarDataIsArray(const V: TVarData): Boolean; function VarDataIsOrdinal(const V: TVarData): Boolean; function VarDataIsFloat(const V: TVarData): Boolean; function VarDataIsNumeric(const V: TVarData): Boolean; function VarDataIsStr(const V: TVarData): Boolean; public constructor Create; overload; constructor Create(RequestedVarType: TVarType); overload; destructor Destroy; override; property VarType: TVarType read FVarType; function IsClear(const V: TVarData): Boolean; virtual; procedure Cast(var Dest: TVarData; const Source: TVarData); virtual; procedure CastTo(var Dest: TVarData; const Source: TVarData; const AVarType: TVarType); virtual; procedure CastToOle(var Dest: TVarData; const Source: TVarData); virtual; // The following two procedures must be overridden by your custom // variant type class. Simplistic versions of Clear and Copy are // available in the protected section of this class but depending on the // type of data contained in your custom variant type those functions // may not handle your situation. procedure Clear(var V: TVarData); virtual; abstract; procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); virtual; abstract; procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operator: TVarOp); virtual; procedure UnaryOp(var Right: TVarData; const Operator: TVarOp); virtual; function CompareOp(const Left, Right: TVarData; const Operator: TVarOp): Boolean; virtual; procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); virtual; end;
要实现自己的 Variant 类型,需要做的就是继承并重载它。如果要了解进一步的详细实现方法,可以参考 fmtbcd.pas 里对 TFMTBcdVariantType 类型的实现。
//variants.pas TInvokeableVariantType = class(TCustomVariantType, IVarInvokeable) protected function FixupIdent(const AText: string): string; virtual; procedure DispInvoke(Dest: PVarData; [Ref] const Source: TVarData; CallDesc: PCallDesc; Params: Pointer); override; public { IVarInvokeable } function DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean; virtual; function DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean; virtual; function GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean; virtual; function SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean; virtual; end; //typinfo.pas TPublishableVariantType = class(TInvokeableVariantType, IVarInstanceReference) protected { IVarInstanceReference } function GetInstance(const V: TVarData): TObject; virtual; abstract; public function GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean; override; function SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean; override; end; //fmtbcd.pas TFMTBcdVariantType = class(TPublishableVariantType) protected function GetInstance(const V: TVarData): TObject; override; public procedure Clear(var V: TVarData); override; procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override; procedure Cast(var Dest: TVarData; const Source: TVarData); override; procedure CastTo(var Dest: TVarData; const Source: TVarData; const AVarType: TVarType); override; procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operator: TVarOp); override; procedure Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult); override; end;
更详细的分析我就不多阐述了,代码是程序员最好的老师,是最准确的表述。