📜 ⬆️ ⬇️

Generic Interfaces in Delphi

A translation by Malcolm Groves, Generic Interfaces in Delphi.

image 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.

image 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/trans
Translation: © r3code.

Source: https://habr.com/ru/post/82709/


All Articles