【发布时间】:2018-08-08 21:21:02
【问题描述】:
我正在根据 Spring4d 的文档示例制作 eventPublisher
不同之处在于订阅者必须明确订阅事件。
我想根据他们是否触发他们的 Handle 程序
实现IEventHandler<TEventType>接口。
发布传入事件时,我使用事件的类名和 Spring4d 的 TType.FindType('IEventHandler<TEvent1>') 找到 IEventHandler<TEventType> 类型引用
然后我遍历我的订阅者(实现 IEventHandler 接口的对象)并检查它是否支持 IEventHandler 类型。
问题是 Supports 方法返回 true 即使订阅者没有实现接口。
另外,我尝试列出TMyEventHandler2 类型的接口。
它包含IEventHandler<TEvent2>??
我相信这是由于 IEventHandler<TEvent2> 的限制
和 IEventHandler<TEvent1> 共享相同的 GUID
有解决办法吗?
使用这些类和接口:
TEvent1 = class(TObject)
end;
TEvent2 = class(TObject)
end;
IEventHandler = interface(IInvokable)
[guid]
procedure Handle(aEvent : TObject);
end;
IEventHandler<T : class> = interface(IEventHandler)
[guid]
procedure Handle(aEvent : T);
end;
TMyEventHandler1 = class(TObject, IEventHandler, IEventHandler<TEvent1>)
public
procedure Handle(AEvent : TObject); overload;
procedure Handle(AEvent : TEvent1); overload;
end;
TMyEventHandler2 = class(TObject, IEventHandler, IEventHandler<TEvent2>)
public
procedure Handle(AEvent : TObject); overload;
procedure Handle(AEvent : TEvent2); overload;
end;
TEventPublisher = class(TObject)
public
fSubscribers : IList<TValue>;
procedure Subscribe(aSubscriber : TValue); // Simply adds the subscriber to the list of subscribers
procedure Publish(aEvent : TObject); // Publishes an event to the subscribers
end;
procedure TEventPublisher.Publish(const event: TObject; ownsObject: Boolean = True);
const
IEventSubscriberName = 'IEventSubscriber<*>';
var
consumerTypeName: string;
consumerType : TRttiType;
intfType : TRttiInterfaceType;
subscriber : TValue;
subscribed : IInterface;
lEventSubscriber: IEventSubscriber;
lIntfs : IReadOnlyList<TRttiInterfaceType>;
begin
consumerTypeName := StringReplace(IEventSubscriberName, '*', GetQualifiedClassName(event), []);
consumerType := TType.FindType(consumerTypeName);
intfType := consumerType as TRttiInterfaceType;
for subscriber in fSubscribers do
begin
lIntfs := TType.GetType(subscriber.AsObject.ClassInfo).GetInterfaces();
// lIntfs for TMyEventHandler2 containts IEventHandler<TEvent1> ???
if Supports(subscriber.AsObject, intfType.GUID, subscribed) then
if Supports(subscriber.AsObject, IEventSubscriber, lEventSubscriber) then
begin
intfType.GetMethod('Handle').Invoke(TValue.From(@subscribed, intfType.Handle), [event])
end;
end;
if ownsObject then
event.Free;
end;
lEventPublisher := TEventPublisher.Create;
lEventPublisher.Subscribe(TMyEventHandler1.Create);
lEventPublisher.Subscribe(TMyEventHandler2.Create);
lEventPublisher.Publish(TEvent1.Create); // Will both trigger TMyEventHandler1.Handle and TMyEventHandler2.Handle. Why ??
【问题讨论】:
-
是的,这是意料之中的,也是单一 guid 的结果
-
是的,这是意料之中的,正如@David 所说,不,没有解决方法,除了在这种情况下不使用 generic 接口。
标签: delphi reflection interface rtti spring4d