我正在基于Spring4d文档的示例创建一个事件发布者。
不同之处在于订阅者必须明确订阅事件。
我想根据他们是否实现了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 ??