Delphi 如何将任意类型的方法传递到过程中并标识它?

Delphi 如何将任意类型的方法传递到过程中并标识它?,delphi,Delphi,我有一个线程库,它有三个用于三种不同方法类型的构造函数。我想把它们合并成一个,然后用某种逻辑在构造函数中区分它们。可能吗?由于有TValue用于值等,那么对于方法类型是否也有类似的情况 我现在支持以下类型: TAgThreadMethod1 = procedure of object; TAgThreadMethod2 = procedure; TAgThreadMethod3 = procedure(const AThread: TAgThread) of object; 施工人员是这样的:

我有一个线程库,它有三个用于三种不同方法类型的构造函数。我想把它们合并成一个,然后用某种逻辑在构造函数中区分它们。可能吗?由于有
TValue
用于值等,那么对于方法类型是否也有类似的情况

我现在支持以下类型:

TAgThreadMethod1 = procedure of object;
TAgThreadMethod2 = procedure;
TAgThreadMethod3 = procedure(const AThread: TAgThread) of object;
施工人员是这样的:

constructor Create(const AOnRun: TAgThreadMethod1); overload; virtual;
constructor Create(const AOnRun: TAgThreadMethod2); overload; virtual;
constructor Create(const AOnRun: TAgThreadMethod3); overload; virtual;
作为参考,我不希望用户在以后的构建之后能够更改worker方法。因此,如果存在一个解决方案,它可以在一个构造函数中完成类似的操作,那么它也是受欢迎的

constructor Create
            (const AOnRun: [Some type which can hold arbitrary method types]);
begin

  // code to identify the method contained in AOnRun.
  // if supported, assign it the correct handler.

end;

没有任何好的方法可以做到这一点,因为方法指针的整个点都将在稍后的某个点被调用,除非您知道它的签名,否则您无法做到这一点。因此,失去签名之间的区别是非常适得其反的


如果您只想在对象中存储一种类型的调用,那么可以让三个构造函数各自创建一个匿名方法,并使用统一的签名包装对这三种类型的调用,然后只存储该方法,而不必处理多个不同的方法类型。但是你所要求的,特别是,不会起作用。

我认为你能做的最好的事情就是拥有一个接受过程类型的最一般形式的构造函数。即
TProc
。这将是主构造函数,唯一的虚拟构造函数。然后可以将其他构造函数委托给主构造函数

概括地说,问题是:

实施方式如下:

constructor TMyClass.Create(AOnRun: TAgThreadMethod1);
begin
  Create(
    procedure(Thread: TAgThread)
    begin
      AOnRun();
    end;
  );
end;

主构造函数,即虚拟构造函数,完成所有工作。其他构造函数(非虚拟构造函数)调整其参数以适应主构造函数的参数

这是可能的,但不仅仅是一个TValue

您可以将其作为trtti方法传递,而不是传递方法本身,如下所示:
MyRegisterMethod(TRttiContext.GetType(TMyClassType.GetMethod('MyMethodName')
如果要传递所有构造函数,则需要使用如下循环:

constructor Create(AOnRun: TAgThreadMethod1); overload;
for MyMethod in TRttiContext.GetType(TMyClassType).GetMethods do
  if MyMethod.IsConstructor then // As in your example you only want constructors
    MyRegisterMethod(MyMethod);
稍后,您可以这样调用此方法:
MyRegisteredMethod.Invoke(nil,MyMethodParams)
。MyMethodParams是一个TValue数组,您需要提供它。这可以存储在TValue本身中(尽管只将它们存储在TArray中可能更容易)。请注意,对于类方法,您只希望在调用中使用
nil


如果要确保参数正常,可以通过在
MyRttiMethod.GetParameters
中查找参数来验证它们,并将它们的实际类型与TValue数组中TValue的实际类型进行比较。这也可以用来找到正确的方法。

好的,我想我明白你的意思了。但是,有没有一种方法可以通过rtti识别方法指针的类型?我试图容纳多种类型的方法,因此我不必为这些方法生成多个构造函数。@Umair:不,无法通过RTTI识别方法指针。在内部,它只是一个指针。您可以对对象执行此操作,因为每个对象都有一个引用其VMT的隐藏字段,VMT有一个指向RTTI表的指针,但方法指针没有类似的内容可供您在运行时进行确定。@Umair:另外,我也不知道您正试图做什么,但当您说“采用多种方法指针类型的线程库”,我想到的第一件事是“我以前在中看到过非常类似的东西。“你看过了吗?我有消息来源,我会调查的。”。谢谢。
TProc
上的参数不是常量。@Stefan我一定在想我自己的版本是常量。有人想知道emba学员的想法是什么。当涉及到类中关联的方法时,您的解决方案确实解决了这个问题,但对于那些不关联的方法,您的解决方案却没有。谢谢你的洞察力。@Umair这是真的。当您将方法声明为类型时,使用Rtti可能仍然是可用的。我现在不能尝试这个,但它确实引起了我的兴趣。也许本周晚些时候我会花时间调查一下。
constructor TMyClass.Create(AOnRun: TAgThreadMethod1);
begin
  Create(
    procedure(Thread: TAgThread)
    begin
      AOnRun();
    end;
  );
end;
for MyMethod in TRttiContext.GetType(TMyClassType).GetMethods do
  if MyMethod.IsConstructor then // As in your example you only want constructors
    MyRegisterMethod(MyMethod);