I am making a eventPublisher based on Spring4d's documentation example
The difference is that subscribers have to explicitly subscribe to events.
I want to trigger their Handle procedure based on wether or not they implement the IEventHandler<TEventType>
interface.
When an incoming event is published, I find the IEventHandler<TEventType>
type reference using the class name of the event and Spring4d's TType.FindType('IEventHandler<TEvent1>')
Then I loop through my subscribers (objects implementing a IEventHandler interface) and check if it supports the IEventHandler type for example.
The problem is that the Supports method returns true even if the subscriber does not implement the interface.
Also, I tried listing the interfaces of say TMyEventHandler2
type. It contains IEventHandler<TEvent2>
??
I beleive this is due to a limitation with the IEventHandler<TEvent2>
and IEventHandler<TEvent1>
sharing the same GUID
Is there a workaround for this ?
Using these classes & interfaces :
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 ??