如何将任意类型的方法传递给程序并识别它?

时间:2014-03-27 21:57:57

标签: delphi

我有一个线程库,它有三个不同方法类型的构造函数。我希望它们合并为一个逻辑,以便在构造函数中区分它们。可能吗?由于值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;

3 个答案:

答案 0 :(得分:5)

没有任何好的方法可以做到这一点,因为方法指针的整个要点稍后会被调用,除非你知道它的签名,否则你不能这样做。因此,失去签名之间的区别非常适得其反。

如果你只想在对象中存储一种类型的调用,你可以让三个构造函数分别创建一个带有统一签名的匿名方法,该签名包含对这三种类型的调用,而只是存储而不是必须存储处理多种不同的方法类型。但是,你所要求的,特别是,不会起作用。

答案 1 :(得分:4)

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

总结一下,declaration in SysUtils是:

type
  TProc<T> = reference to procedure(Arg1: T);

所以你的主构造函数是:

constructor Create(AOnRun: TProc<TAgThread>); overload; virtual;

其他构造函数不是虚拟的,可能如下所示:

constructor Create(AOnRun: TAgThreadMethod1); overload;

实施为:

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

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

答案 2 :(得分:1)

这是可能的,但不仅仅是TValue。

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

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进行比较。这也可用于找到正确的方法。