Y
yanfei0891_firs
Unregistered / Unconfirmed
GUEST, unregistred user!
怎样按名字调用某个类的方法?(在 不知道方法的参数个数及类型 的条件下)
这篇文章 http://www.tommstudio.com/newclub30/d_displayjqxw.asp 提供了
一种方法可以调用,但当方法的参数有real,或者currency型时 传入的参数值
就不对了,大家知道是为什么吗?
具体的程序如下:
调用的方法:
function ExecuteRoutine(AObj: TObject; AName: string;
Params: array of const): DWord;
const
RecSize = SizeOf(TVarRec); // 循环处理参数列表时递增的字节数
var
PFunc: Pointer;
ParCount: DWord;
begin
if not Assigned(AObj) then
raise Exception.Create ('你确定传进来的是一个对象?');
PFunc := AObj.MethodAddress(AName); // 获取方法地址
if not Assigned(PFunc) then
raise Exception.CreateFmt('找不到 %s 的 Method: %s', [AObj.ClassName,
AName]);
ParCount := High(Params) + 1; // 获取参数个数
asm
PUSH ESI // 保存 ESI,我们待会儿要用到它
MOV ESI, Params // ESI 指向参数表首址
CMP ParCount, 1 // 判断参数个数
JB @NoParam
JE @OneParam
CMP ParCount, 2
JE @TwoParams
@ManyParams: // 超过两个参数
CLD // 清空方向标志
MOV ECX, ParCount
SUB ECX, 2 // 循环 ParCount - 2 次
MOV EDX, RecSize // EDX 依次指向每个参数的首址,每次递增 8 Bytes
ADD EDX, RecSize // 跳过前两个参数
@ParamLoop:
MOV EAX, [ESI][EDX] // 用基址变址寻址方式取得一个参数
PUSH EAX // 参数进栈
ADD EDX, RecSize // EDX 指向下一个参数首址
LOOP @ParamLoop
@TwoParams: // 两个参数
MOV ECX, [ESI] + RecSize
@OneParam: // 一个参数
MOV EDX, [ESI]
@NoParam:
MOV EAX, AObj // 传入实例地址(即,隐藏参数 Self)
CALL PFunc // 调用方法
MOV Result, EAX // 返回值放入 Result
POP ESI // 记得还原
end;
end;
被调用的方法
procedure TForm1.avg(Const a,b : Currency;var c : Currency);
begin
c := (a + b)/2 ;
end;
调用:
begin
var j : Currency;
ExecuteRoutine(Form1,'avg',[12.21,12.32,@j]);
end;
调用时跟踪 a,b的值都不对了,但如果 a,b设成integer型就可以了
这篇文章 http://www.tommstudio.com/newclub30/d_displayjqxw.asp 提供了
一种方法可以调用,但当方法的参数有real,或者currency型时 传入的参数值
就不对了,大家知道是为什么吗?
具体的程序如下:
调用的方法:
function ExecuteRoutine(AObj: TObject; AName: string;
Params: array of const): DWord;
const
RecSize = SizeOf(TVarRec); // 循环处理参数列表时递增的字节数
var
PFunc: Pointer;
ParCount: DWord;
begin
if not Assigned(AObj) then
raise Exception.Create ('你确定传进来的是一个对象?');
PFunc := AObj.MethodAddress(AName); // 获取方法地址
if not Assigned(PFunc) then
raise Exception.CreateFmt('找不到 %s 的 Method: %s', [AObj.ClassName,
AName]);
ParCount := High(Params) + 1; // 获取参数个数
asm
PUSH ESI // 保存 ESI,我们待会儿要用到它
MOV ESI, Params // ESI 指向参数表首址
CMP ParCount, 1 // 判断参数个数
JB @NoParam
JE @OneParam
CMP ParCount, 2
JE @TwoParams
@ManyParams: // 超过两个参数
CLD // 清空方向标志
MOV ECX, ParCount
SUB ECX, 2 // 循环 ParCount - 2 次
MOV EDX, RecSize // EDX 依次指向每个参数的首址,每次递增 8 Bytes
ADD EDX, RecSize // 跳过前两个参数
@ParamLoop:
MOV EAX, [ESI][EDX] // 用基址变址寻址方式取得一个参数
PUSH EAX // 参数进栈
ADD EDX, RecSize // EDX 指向下一个参数首址
LOOP @ParamLoop
@TwoParams: // 两个参数
MOV ECX, [ESI] + RecSize
@OneParam: // 一个参数
MOV EDX, [ESI]
@NoParam:
MOV EAX, AObj // 传入实例地址(即,隐藏参数 Self)
CALL PFunc // 调用方法
MOV Result, EAX // 返回值放入 Result
POP ESI // 记得还原
end;
end;
被调用的方法
procedure TForm1.avg(Const a,b : Currency;var c : Currency);
begin
c := (a + b)/2 ;
end;
调用:
begin
var j : Currency;
ExecuteRoutine(Form1,'avg',[12.21,12.32,@j]);
end;
调用时跟踪 a,b的值都不对了,但如果 a,b设成integer型就可以了