在反射调用方法时,常常会遇到var或out形式的参数,但是Delphi的ObjAuto单元却是不支持如此做的,因此,需要对反射的单元做一些修改,以使其支持var类型的参数
对于var和out两种类型,在Delphi的编译器看来,它们的处理是一样的,只不过out参数会在传入时,先进行一次clear操作。但是其本质还是var,因此,我们将这两种形式的参数放在一起讨论。
从CodeGear提供的ObjAuto.pas中,能够找到这么一句话, For pfVar, the variant must be a byref and equal to the type . 意思即是说,对于var型的参数,必须传入引用,由此,用一个简单的指针操作,把变量变为引用即可。
function Reference( const V: Variant; VarTyp: TVarType): Variant;
var
vType: TVarType;
begin
if VarIsByRef(V) then
Result := V
else if VarIsArray(V, False) then
Result := VarArrayRef(V)
else
begin
VarClear(Result);
vType := VarTyp;
if vType in [varSmallint, varInteger, varSingle, varDouble,
varCurrency, varDate, varOleStr, varDispatch,
varError, varBoolean, varUnknown,
varShortInt, varByte ,varWord, varLongWord, varInt64] then
TVarData(Result).VType := vType or varByRef
else
TVarData(Result).VType := varInteger or varByRef;
TVarData(Result).VPointer := @TVarData(V).VPointer;
end ;
end ;
通过这个函数,就可以把一个变量,变成变量的引用。当然了,有了引用之后,我们需要解引用
用一个功能相反的函数即可:
function Unreference( const V: Variant; VarTyp: TVarType): Variant;
var
vValue: Variant;
begin
if not VarIsByRef(V) then
Result := V
else
begin
VarClear(vValue);
TVarData(vValue).VType := VarTyp;
TVarData(vValue).VPointer := Pointer((TVarData(V).VPointer)^);
Result := vValue;
end ;
end ;
然后还需要修改一下ObjAuto.pas
把里面的 For pfVar, the variant must be a byref and equal to the type. 下面的两行代码注释掉,也就是不进行var或out的校验
这样,我们的准备工作就完成了,下面就是用一个实例来试试var的调用。
首先做一个测试类,里面包含一个带有var参数的方法
如: procedure TestVar(AName: string ; AInt: integer; var a: string ; var b: integer);
然后按以下方式调用之:
var
v1 : string ;
v2: integer;
vref1: Variant;
vref2: variant;
vRet: Variant;
begin
v1 := 'Test Str';
v2 := 123;
// 变量转换成引用
vref1 := Reference(v1, varString);
vref2 := Reference(v2, varInteger);
// 获取方法的反射信息
mi := GetMethodInfo(FInstance, 'TestVar');
// 调用方法,调用时传入变量的引用
ObjectInvoke(FInstance, mi, [1,2,3,4], ['1111',999, vRef1, vref2]);
// 解引用
vRet := Unreference(vref1, varString);
ShowMessage(vRet);
vRet := Unreference(vref2, varInteger);
ShowMessage(vRet);
end ;
以上例子中,传入的变量引用,在被操作后,依然以引用的形式传了回来
通过解引用的操作即可得到它的值。
对于var和out两种类型,在Delphi的编译器看来,它们的处理是一样的,只不过out参数会在传入时,先进行一次clear操作。但是其本质还是var,因此,我们将这两种形式的参数放在一起讨论。
从CodeGear提供的ObjAuto.pas中,能够找到这么一句话, For pfVar, the variant must be a byref and equal to the type . 意思即是说,对于var型的参数,必须传入引用,由此,用一个简单的指针操作,把变量变为引用即可。
function Reference( const V: Variant; VarTyp: TVarType): Variant;
var
vType: TVarType;
begin
if VarIsByRef(V) then
Result := V
else if VarIsArray(V, False) then
Result := VarArrayRef(V)
else
begin
VarClear(Result);
vType := VarTyp;
if vType in [varSmallint, varInteger, varSingle, varDouble,
varCurrency, varDate, varOleStr, varDispatch,
varError, varBoolean, varUnknown,
varShortInt, varByte ,varWord, varLongWord, varInt64] then
TVarData(Result).VType := vType or varByRef
else
TVarData(Result).VType := varInteger or varByRef;
TVarData(Result).VPointer := @TVarData(V).VPointer;
end ;
end ;
通过这个函数,就可以把一个变量,变成变量的引用。当然了,有了引用之后,我们需要解引用
用一个功能相反的函数即可:
function Unreference( const V: Variant; VarTyp: TVarType): Variant;
var
vValue: Variant;
begin
if not VarIsByRef(V) then
Result := V
else
begin
VarClear(vValue);
TVarData(vValue).VType := VarTyp;
TVarData(vValue).VPointer := Pointer((TVarData(V).VPointer)^);
Result := vValue;
end ;
end ;
然后还需要修改一下ObjAuto.pas
把里面的 For pfVar, the variant must be a byref and equal to the type. 下面的两行代码注释掉,也就是不进行var或out的校验
这样,我们的准备工作就完成了,下面就是用一个实例来试试var的调用。
首先做一个测试类,里面包含一个带有var参数的方法
如: procedure TestVar(AName: string ; AInt: integer; var a: string ; var b: integer);
然后按以下方式调用之:
var
v1 : string ;
v2: integer;
vref1: Variant;
vref2: variant;
vRet: Variant;
begin
v1 := 'Test Str';
v2 := 123;
// 变量转换成引用
vref1 := Reference(v1, varString);
vref2 := Reference(v2, varInteger);
// 获取方法的反射信息
mi := GetMethodInfo(FInstance, 'TestVar');
// 调用方法,调用时传入变量的引用
ObjectInvoke(FInstance, mi, [1,2,3,4], ['1111',999, vRef1, vref2]);
// 解引用
vRet := Unreference(vref1, varString);
ShowMessage(vRet);
vRet := Unreference(vref2, varInteger);
ShowMessage(vRet);
end ;
以上例子中,传入的变量引用,在被操作后,依然以引用的形式传了回来
通过解引用的操作即可得到它的值。