使用 RTTI 方法调用返回的函数引用
Using function reference returned by RTTI method invocation
在 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 自己,而只需向他们的 class 添加一个属性,然后传递一个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 类型的函数引用。
只需使用 .AsType<TDelegate>()
- 这 return 是 TValue
的内容 TDelegate
。该功能还确保您不会将 TValue
内的内容变成不明确赋值兼容的内容(不像 Variants 那样)。但由于这是您的函数的确切 return 类型,因此它会正常工作。
P.S。您需要明确键入括号,否则编译器可能会出现 E2010 错误。
在 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 自己,而只需向他们的 class 添加一个属性,然后传递一个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 类型的函数引用。
只需使用 .AsType<TDelegate>()
- 这 return 是 TValue
的内容 TDelegate
。该功能还确保您不会将 TValue
内的内容变成不明确赋值兼容的内容(不像 Variants 那样)。但由于这是您的函数的确切 return 类型,因此它会正常工作。
P.S。您需要明确键入括号,否则编译器可能会出现 E2010 错误。