使用RTTI方法调用返回的函数引用

时间:2018-11-20 10:56:52

标签: delphi rtti delphi-10.2-tokyo

在Delphi程序中,具有以下模式:

TDelegate=reference to procedure(const Arg: TMyType); 

TRouter = class
  ...
public
  procedure RegisterHandler(const route: string: handler: TDelegate);
end;

THandlerContainer = class
public
  function getDelegate: TDelegate;
  procedure register(const Router: TRouter);
end; // class

...
procedure THandlerContainer.register(const router: TRouter)
begin
  router.RegisterHandler('route', getDelegate);
end;

基本上,我正在注册用于处理某些消息处理的函数引用(基于“ route”字符串)。

我想简化我的同事的模式,以便他们不必为每个实现调用router.RegisterHandler自己,而只需向其类添加一个属性,然后将一个实例传递给TRouter的方法即可,使用RTTI查找该属性修饰的所有方法并进行注册。

因此,我为此装饰创建了一个简单属性RegisterMessageHandlerAttribute(使用用于接收路由字符串的自定义构造函数)并编写了TRouter方法,该方法使用RTTI查找所有用该属性装饰的方法:

function TRouter.RegisterHandlers(const HandlerContainerClass:
    TObject);
var
  RTTIContext: TRttiContext;
  RttiType : TRttiType;
  prop: TRttiMethod;
  Attr: TCustomAttribute;
begin
  RTTIContext := TRttiContext.Create;
  try
    RttiType := RTTIContext.GetType(HandlerContainerClass);
    if assigned(RttiType) then
    begin
      for prop in RttiType.GetMethods do
      begin
         for Attr in Prop.GetAttributes do
         begin
           if (Attr is RegisterMessageHandlerAttribute) then
           begin
               Self.RegisterHandler(
                (Attr as RegisterMessageHandlerAttribute).Route,
                TDelegate(Prop.Invoke(HandlerContainerClass, []).AsPointer); // <--- this fails
               );
           end;
         end;
      end;
    end;
  finally
    RTTIContext.Free;
  end;
  result := Handlers.ToArray;
end;

不幸的是,编译器在我通过调用方法检索lambda的那一行上抱怨:

TDelegate(Prop.Invoke(HandlerContainerClass, []).AsPointer);
...
[dcc32 Error] GIT.MessageQueue.Router.pas(169): E2089 Invalid typecast

我的问题是我不知道如何获取Prop.Invoke返回的TValue类型并将其用作TDelegate类型的函数引用。

1 个答案:

答案 0 :(得分:3)

只需使用.AsType<TDelegate>()-这将TValue的内容作为TDelegate返回。该函数还确保您不会将TValue内部的内容转换为与指定分配不兼容的内容(与Variants不同)。但是,由于这是函数的确切返回类型,因此它将正常工作。

P.S。您需要明确输入括号,否则可能会从编译器收到E2010错误。