You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将普通过程绑定到TGetStrProc事件后参数为空的问题排查

问题分析:普通过程作为TGetStrProc时参数为空的原因

首先得明确Delphi中普通过程指针和带of object的方法指针的本质区别——这就是问题的核心所在。

你尝试用MakeMethod(nil, @ProcLogging)把普通全局过程转成TGetStrProc类型,但TGetStrProc的定义是:

TGetStrProc = procedure(const S: string) of object;

带of object的方法指针在调用时,会自动把对象实例(也就是TMethod.Data的值)作为第一个隐藏参数压入调用栈,之后才会传递显式定义的const S: string参数。

而你的ProcLogging是普通全局过程,它的调用约定是直接接收显式参数const msg: string作为第一个(也是唯一一个)参数。当你通过方法指针调用它时,实际的调用栈逻辑是:

  1. 先压入TMethod.Data的值(也就是你传入的nil)
  2. 再压入真正要传递的字符串'Doing the work'

但ProcLogging会把栈顶的第一个值(nil)当作自己的msg参数,而nil对于string类型来说等价于空字符串,这就是为什么你看到ProcLogging接收到的内容是空的。

解决方案

有几种可行的解决方式,根据你的代码场景选择即可:

1. 写一个适配方法指针的包装过程

新增一个符合方法指针调用约定的适配器过程,在内部调用你的普通过程:

procedure LoggingAdapter(Self: TObject; const msg: string);
begin
  ProcLogging(msg); // 忽略Self参数,直接传递真正的消息
end;

然后在赋值事件时,把MakeMethod的Code指向这个适配器:

obj.OnLog := TGetStrProc(MakeMethod(nil, @LoggingAdapter));

2. 修改TMyObject的事件类型(如果允许)

如果你的日志回调不需要绑定到对象实例,可以把OnLog的类型改成不带of object的普通过程类型:

type
  TGetStrProcNonObject = procedure(const S: string);

  TMyObject = class
  strict private
    _onLog: TGetStrProcNonObject;
    procedure _log(const msg: string);
  public
    procedure DoTheWork();
    property OnLog: TGetStrProcNonObject read _onLog write _onLog;
  end;

这样直接赋值普通过程即可,完全不需要MakeMethod:

obj.OnLog := ProcLogging;

3. 把普通过程改成类的静态方法

如果你的日志逻辑适合封装成类的静态方法,也可以直接使用:

type
  TLogUtils = class
  public
    class procedure ProcLogging(const msg: string); static;
  end;

class procedure TLogUtils.ProcLogging(const msg: string);
begin
  mbox(Format('ProcLogging: "%s"', [msg]));
end;

赋值时直接绑定静态方法即可,静态方法不需要实例,天然符合of object方法指针的调用约定:

obj.OnLog := TLogUtils.ProcLogging;
验证效果

采用任意一种方案修改后,运行代码就能得到你预期的输出:

TMyObject._log: "Doing the work"
ProcLogging: "Doing the work"

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 10:32:56