В программе на 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;
К сожалению, компиляторы жалуются на строку, где я извлекаю лямбда, вызывая метод:
TDelegate(Prop.Invoke(HandlerContainerClass, []).AsPointer);
...
[dcc32 Error] GIT.MessageQueue.Router.pas(169): E2089 Invalid typecast
Моя проблема в том, что я понятия не имею, как взять тип TValue, возвращенный Prop.Invoke и используйте его как ссылку на функцию типа TDelegate.