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;更详细的分析我就不多阐述了,代码是程序员最好的老师,是最准确的表述。
