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

Pascal如何构建可管理不同procedure of object类型的泛型类

解决方案

Delphi 原生泛型暂不支持将 procedure of object 作为类型参数的编译期约束,可通过以下两种方案实现相同的通用回调管理能力:

方案1:全平台通用实现(运行时类型校验)

所有 procedure of object/function of object 类型本质都是 TMethod 结构,我们可以通过运行时校验泛型参数的类型信息,实现通用基类,仅在传入非方法类型时报错。通用逻辑(订阅、取消订阅等)全部封装在基类中,仅触发回调的逻辑按不同签名在子类实现即可。

代码实现

unit FunctionManager;

interface

uses
  System.SysUtils, System.Generics.Collections, System.TypInfo;

type
  // 通用泛型回调管理器基类
  TFunctionManager<T> = class(TList<T>)
  public
    constructor Create;
    // 订阅回调:可扩展去重、优先级等逻辑
    procedure Subscribe(fnCallback: T);
    // 取消订阅
    procedure Unsubscribe(fnCallback: T);
  end;

  // 无参数通知回调管理器示例
  TNotifyEventManager = class(TFunctionManager<TNotifyEvent>)
  public
    procedure FireCallbacks(Sender: TObject);
  end;

  // 带Int参数返回布尔值的回调管理器示例
  TNotifyIntEventManager = class(TFunctionManager<TNotifyIntEvent>)
  public
    // 示例逻辑:所有回调返回True时整体返回True,否则返回False
    function FireCallbacks(Sender: TObject; Value: Integer): Boolean;
  end;

implementation

{ TFunctionManager<T> }

constructor TFunctionManager<T>.Create;
begin
  inherited Create;
  // 运行时校验泛型参数必须是方法类型
  if PTypeInfo(TypeInfo(T))^.Kind <> tkMethod then
    raise EInvalidCast.Create('泛型参数T必须是方法指针(of object)类型');
end;

procedure TFunctionManager<T>.Subscribe(fnCallback: T);
begin
  // 可添加重复订阅校验逻辑
  if IndexOf(fnCallback) = -1 then
    Add(fnCallback);
end;

procedure TFunctionManager<T>.Unsubscribe(fnCallback: T);
begin
  Remove(fnCallback);
end;

{ TNotifyEventManager }

procedure TNotifyEventManager.FireCallbacks(Sender: TObject);
var
  ev: TNotifyEvent;
begin
  for ev in Self do
    ev(Sender);
end;

{ TNotifyIntEventManager }

function TNotifyIntEventManager.FireCallbacks(Sender: TObject; Value: Integer): Boolean;
var
  ev: TNotifyIntEvent;
begin
  Result := True;
  for ev in Self do
  begin
    if not ev(Sender, Value) then
      Result := False;
  end;
end;

使用示例

// 实例化不同类型的回调管理器
var
  notifyMgr: TNotifyEventManager;
  intNotifyMgr: TNotifyIntEventManager;
begin
  notifyMgr := TNotifyEventManager.Create;
  // 订阅回调
  notifyMgr.Subscribe(MyNotifyProc);
  // 触发所有回调
  notifyMgr.FireCallbacks(Self);
  // 取消订阅
  notifyMgr.Unsubscribe(MyNotifyProc);
  notifyMgr.Free;
end;

方案2:Free Pascal专属实现(编译期约束)

Free Pascal 3.0及以上版本原生支持方法类型作为泛型约束,可直接按你预期的写法实现:

{$mode objfpc}
{$modeswitch advancedrecords}
{$modeswitch generics}

uses
  Contnrs, Generics.Collections;

type
  // 直接声明带方法类型约束的泛型类
  generic TFunctionManager<T: procedure of object> = class(specialize TList<T>)
  public
    procedure Subscribe(fnCallback: T);
    procedure Unsubscribe(fnCallback: T);
    // 其余通用方法
  end;

注意事项

  • 运行时校验会在类实例化时触发,开发阶段即可发现传入非法类型的问题,不会影响线上运行性能
  • 不同签名的回调触发逻辑无法通用,需根据业务需求在对应子类实现即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 23:06:04