如何在delphi中的一个容器中存储不同的方法指针?

Nas*_*out 1 delphi

我有以下方法指针

type
  TMethod1 = procedure(aValue: TType1) of object;
  TMethod2 = procedure(aValue: TType2) of object;
  .
  .
  TMethodN = procedure(aValue: TTypeN) of object;
Run Code Online (Sandbox Code Playgroud)

我想将它们存放在一个容器中.

我找到了这个答案,其中一个指针TMethod1用于存储一个方法,然后调用它.但是,我宁愿不使用它,原因如下:

  • 它分配了新的内存块,然后我应该决定何时释放它(从来没有将它从一个区域中取出).

  • 它假设所有方法都有相同的定义,这不是我的情况.

  • 这是一种方法.我有一个他们的阵列,我不知道我将如何维持这样的存储.

文档中有一个使用TMethod方法的例子,但是以不同的方式不再需要上面的第二个假设.在调用该方法的最后一步中,我必须做一个不安全的类型转换,这也是我想要远离的东西.

我该如何做到这一点?

澄清我将如何使用这些方法:

我有一个

procedure DoWork(aData: TType1; method: TMethod1);
begin
  store aData in a field;
  store method in my container; 
end;
Run Code Online (Sandbox Code Playgroud)

然后,处理aData和调用method.

Rem*_*eau 6

无论您在容器中存储的是什么,都必须是相同的类型.你可以用TMethod它.它是RTL提供的特殊记录类型,表示任何 of object方法指针.

困难的部分是调用存储在容器中的方法.你不能直接调用TMethod,你必须知道它指向的确切方法类型,然后将其类型转换为该类型.例如:

var
  Field: TObject; // assuming TType... are class types
  Container: TList<TMethod>;

procedure DoWork<T>(aData: T; method: procedure(aValue: T) of object);
var
  M: TMethod;
begin
  M := TMethod(method);
  Field := aData;
  Container.Add(M); 
end;

procedure CallFieldMethod;
var
  M: TMethod;
begin
  M := Container[Index];
  if Field.ClassType = TType1 then
  begin
    TMethod1(M)(TType1(Field));
  end
  else if Field.ClassType = TType2 then
  begin
    TMethod2(M)(TType2(Field));
  end
  ...
end;

...

procedure TSomeClass.MethodForType1(aValue: TType1);
begin
  // use aValue as needed...
end;

DoWork<TType1>(Type1Obj, MethodForType1);

...

procedure TSomeClass.MethodForType2(aValue: TType2);
begin
  // use aValue as needed...
end;

DoWork<TType2>(Type2Obj, MethodForType2);

...
Run Code Online (Sandbox Code Playgroud)

另一种解决方案是完全不依赖于特定类型,只需为容器定义1种方法类型.让来电者DoWork()决定做什么:

type
  TMyMethod = procedure(aValue: Pointer) of object;

var
  Field: Pointer;
  Container: TList<TMyMethod>;

procedure DoWork(aData: Pointer; method: TMyMethod);
begin
  Field := aData;
  Container.Add(method); 
end;

procedure CallFieldMethod;
begin
  Container[Index](Field);
end;

...

procedure TSomeClass.MethodForType1(aValue: Pointer);
begin
  // use TType1(aValue) as needed...
end;

DoWork(Type1Obj, MethodForType1);

...

procedure TSomeClass.MethodForType2(aValue: Pointer);
begin
  // use TType2(aValue) as needed...
end;

DoWork(Type2Obj, MethodForType2);

...
Run Code Online (Sandbox Code Playgroud)