Home How to store different method pointers in one container in delphi?
Reply: 1

How to store different method pointers in one container in delphi?

Nasreddine Abdelillah Galfout
1#
Nasreddine Abdelillah Galfout Published in 2017-11-14 20:27:01Z

I have the following method pointers

type
  TMethod1 = procedure(aValue: TType1) of object;
  TMethod2 = procedure(aValue: TType2) of object;
  .
  .
  TMethodN = procedure(aValue: TTypeN) of object;

I want to store them in one container.

I found this answer, where a pointer to TMethod1 is used to store one method and then call it. However, I would rather not use it for the following reasons:

  • It allocates new block of memory and then later I should decide when to free it(never made it out of that area in one piece).

  • It assumes all methods have the same definition, which is not my case.

  • It is for one method. I have an array of them, and I do not see how I'm going to maintain such storage.

And there is an example in the documentation which uses a TMethod approach, but in a different way where the second assumption above is no longer needed. In the last step to call the method, I have to do an unsafe typecast, which again is something I would like to stay away from.

How do I accomplish this?

Clarification on how I'm going to use these methods:

I have a

procedure DoWork(aData: TType1; method: TMethod1);
begin
  store aData in a field;
  store method in my container; 
end;

Then later, process aData and call method.

Remy Lebeau
2#
Remy Lebeau Reply to 2017-11-14 22:08:33Z

Whatever you store in your container must be the same type. You can use TMethod for that. It is a special record type provided by the RTL to represents any of object method pointer.

The hard part is going to be calling the methods that are stored in your container. You can't just call TMethod directly, you have to know the exact method type that it is pointing at, then type-cast it to that type. For example:

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);

...

Another solution is to not rely on specific types at all, and just define 1 method type for the container. Let the caller of DoWork() decide what to do:

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);

...
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.327217 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO