考虑这个用于方法跟踪的典型代码(为说明而简化):
type
IMethodTracer = interface
end;
TMethodTracer = class(TInterfacedObject, IMethodTracer)
private
FName: String;
FResultAddr: Pointer;
FResultType: PTypeInfo;
public
constructor Create(
const AName: String;
const AResultAddr: Pointer = nil;
const AResultType: PTypeInfo = nil);
destructor Destroy; override;
end;
constructor TMethodTracer.Create(
const AName: String;
const AResultAddr: Pointer;
const AResultType: PTypeInfo);
begin
inherited Create();
FName := AName;
FResultAddr := AResultAddr;
FResultType := AResultType;
Writeln('Entering ' + FName);
end;
destructor TMethodTracer.Destroy;
var
lSuffix: String;
lResVal: TValue;
begin
lSuffix := '';
if FResultAddr <> nil then
begin
//there's probably a more straight-forward to doing this, without involving TValue:
TValue.Make(FResultAddr, FResultType, lResVal);
lSuffix := ' - Result = ' + lResVal.AsString;
end;
Writeln('Leaving ' + FName + lSuffix);
inherited Destroy;
end;
function TraceMethod(
const AName: String;
const AResultAddr: Pointer;
const AResultType: PTypeInfo): IMethodTracer;
begin
Result := TMethodTracer.Create(AName, AResultAddr, AResultType);
end;
//////
function F1: String;
begin
TraceMethod('F1', @Result, TypeInfo(String));
Writeln('Doing some stuff...');
Result := 'Booyah!';
end;
F1();
这是按预期工作的。输出是:
进入 F1
做一些事情...
离开 F1 - 结果 = Booyah!
我现在正在寻找一种方法来最小化调用所需参数的数量TraceMethod()
,理想情况下允许我完全跳过 -Result
相关的参数。我自己没有汇编程序或堆栈布局的经验,但如果我没记错的话,从我看到其他人所做的“魔法”来看,至少隐含的魔法Result
变量的内存地址应该可以通过某种方式获得,不是吗? ? 也可能有人可以从那里获得它的类型信息?
当然,如果甚至可以确定“周围”函数本身的名称,这将消除将参数传递给TraceMethod
完全...
我正在使用 Delphi XE2,因此可以使用所有最近引入的语言/框架功能。
在任何人提到它之前:我的实际代码已经使用CodeSite.EnterMethod
/ExitMethod
而不是Writeln
-calls。我也知道这个简化的例子不能处理复杂的类型并且不执行任何错误处理。