A translation by Malcolm Groves, Generic Interfaces in Delphi.
Most generic use cases in Delphi use a generic type class. However, while working on my project, I decided that I needed an interface with a generic type.
The project uses a built-in
publisher-subscriber mechanism. I wanted the subscriber to have a separate
Receive method for each type of event, rather than a separate method with a huge
case expression that chooses an action for each type of event. Also, I did not want to define an interface for each type of event. I needed a generic subscriber interface, which receives the event type as a parameter.
')
However, I had no idea if I could define a generic interface, let alone implement it. Even assuming that I can do this, can Delphi choose the right
Receive method to call? There is only one way to find out ...
Please note: in this example, some parts of the code are removed, only those parts that are necessary to demonstrate the generic interfaces are left. I will talk about other parts in my next posts.
First, I described a few simple events. Their content is not so interesting:
TSomeEvent = class
// other stuff
end;
TSomeOtherEvent = class
// other stuff
end;
Then, I defined the generic interface
ISubscriber<T> = interface
procedure Receive(Event : T);
end;
This interface must be implemented by subscribers to receive different types of events. Notice that the type of event is recorded as a generic type
T.Subscribers must then implement an interface for each type of event they want to receive. Since this is a generic interface - it is quite simple:
TMySubscribingObject = class(TInterfacedObject, ISubscriber<TSomeEvent>, ISubscriber<TSomeOtherEvent>)
protected
procedure Receive(Event : TSomeEvent); overload;
procedure Receive(Event : TSomeOtherEvent); overload;
end;
There is no description of the interfaces
ISomeEventSubscriber and
ISomeOtherEventSubscriber , we can simply use
ISubscriber <T> and transfer the type in place. To do this, you must implement the necessarily overloaded
Receive method.
The above code describes the basis of the idea. You will find the rest of the code in the corresponding
test project . We implement several interfaces, each of which has strongly typed
Receive events, without actually defining each of these interfaces.
And does it work? From the first attempt - no, it did not work out. Regardless of what type of event and through which interface I transmitted, the last
Receive method was always executed.
dunit_generic_interfaces Life Rule # 37: If it’s about choosing between the confusing Malcolm and the developers of the Delphi compiler, this is probably Malcolm’s mistake.
Yes, my mistake.
Barry Kelly pointed out the mistakes of my approach. I described a generic interface with a
GUID . Habit. This means that
ISubscriber <TSomeEvent> and
ISubscriber <TSomeOtherEvent> , and any other interfaces defined by this generic will have the same
GUID . Together with using the "
as " operator to get the reference from the
TMySubscribingObject instance, this confused Delphi and always forced to return the same interface reference.
Removed
GUID and "
as " - everything worked fine.
In future posts I will show other parts: the publisher and the Broker of events. An interesting side effect of the definition of events that the class introsses in is that the event broker can simply check the interfaces implemented by subscribers to find out which events they are subscribed to.
You can help improve the translation.translated.by/you/generic-interfaces-in-delphi/into-ru/transTranslation: © r3code.