{"id":420,"date":"2009-07-27T22:07:19","date_gmt":"2009-07-27T12:07:19","guid":{"rendered":"http:\/\/www.malcolmgroves.com\/blog\/?p=420"},"modified":"2015-03-13T10:36:50","modified_gmt":"2015-03-12T23:36:50","slug":"generic-interfaces-in-delphi","status":"publish","type":"post","link":"http:\/\/www.malcolmgroves.com\/blog\/?p=420","title":{"rendered":"Generic Interfaces in Delphi"},"content":{"rendered":"<p>Most of the examples I\u2019ve seen of Generics in Delphi, use classes containing a generic type. However, while working on a personal project, I decided I wanted an Interface containing a generic type.<\/p>\n<p>The project uses an in-process <a href=\"http:\/\/en.wikipedia.org\/wiki\/Publish\/subscribe\" target=\"_blank\">publish\/subscribe<\/a> mechanism, and I wanted a subscriber to have a separate Receive method for each event type, rather than a single method which contained a big case statement with branches for each event type. Equally, however, I didn\u2019t want to have to define an interface type for each event type. What I wanted was to have a generic Subscriber interface, that took the event type as a parameter.<\/p>\n<p>However, I had no idea if I could define a generic Interface, let alone implement one. Even assuming I could do both of those things, would Delphi be able to resolve the correct Receive method to invoke? Only one way to find out\u2026.<\/p>\n<p>NB: In this example, I\u2019ve stripped out most of the pub\/sub stuff, just leaving the pieces needed to show the generic interfaces. I\u2019ll write about the other pieces over the next few posts.<\/p>\n<p>First, I implemented a few sample events. The contents of these are not that interesting:<\/p>\n<pre lang=\"Delphi\">TSomeEvent = class\r\n  \/\/ other stuff \r\nend;\r\n\r\nTSomeOtherEvent = class\r\n  \/\/ other stuff \r\nend;<\/pre>\n<p>Then, I defined a generic interface<\/p>\n<pre lang=\"Delphi\">ISubscriber = interface\r\n  procedure Receive(Event : T); \r\nend;<\/pre>\n<p>This is the interface that will need to be implemented by my subscribers in order to receive events of a particular type. Note, the type of event is set up as a generic type T.<\/p>\n<p>Then, my subscribers need to implement an interface for each Event type they want to receive, however because it is a generic interface, it\u2019s pretty straight-forward:<\/p>\n<pre lang=\"Delphi\">TMySubscribingObject = class(TInterfacedObject, ISubscriber, ISubscriber)\r\nprotected\r\n  procedure Receive(Event : TSomeEvent); overload; \r\n  procedure Receive(Event : TSomeOtherEvent); overload; \r\nend;<\/pre>\n<p>Note there\u2019s no definition of a ISomeEventSubscriber and a ISomeOtherEventSubscriber interface, we can just use ISubscriber&lt;T&gt; and pass the type in in-place. We just need to implement the necessary overloaded Receive events.<\/p>\n<p>You can see the rest of the code in the <a href=\"https:\/\/github.com\/malcolmgroves\/delphi-experiments\/tree\/master\/GenericInterfaces\" target=\"_blank\">associated test project<\/a>, but the above shows you the main aim. Implementing multiple interfaces, each with a strongly-typed Receive event, without actually having to define each of those interfaces.<\/p>\n<p>So, does it work? Well, at my first attempt, no, it didn\u2019t. No matter what type of Event I passed in, or via what interface, it always invoked the last Receive method.<\/p>\n<p><a href=\"http:\/\/www.malcolmgroves.com\/blog\/wp-content\/uploads\/2009\/07\/dunit-generic-interfaces1.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"margin: 0px 10px 0px 0px; display: inline; border: 0px;\" title=\"dunit_generic_interfaces\" src=\"http:\/\/www.malcolmgroves.com\/blog\/wp-content\/uploads\/2009\/07\/dunit-generic-interfaces-thumb1.jpg\" alt=\"dunit_generic_interfaces\" width=\"228\" height=\"244\" align=\"left\" border=\"0\" \/><\/a>Rule of life #37: If it\u2019s a choice between Malcolm having screwed up or the Delphi compiler architects, it\u2019s probably Malcolm\u2019s fault.<\/p>\n<p>Yes, my bad. <a href=\"http:\/\/barrkel.blogspot.com\/\" target=\"_blank\">Barry Kelly<\/a> eventually pointed out the error of my ways. I\u2019d originally defined the generic Interface with a GUID. Habit, really. However, this meant that both ISubscriber&lt;TSomeEvent&gt; and ISubscriber&lt;TSomeOtherEvent&gt;, and indeed any other interface I defined off this generic interface, would have the same GUID. This combined with the fact that I was using an \u201cas\u201d cast to get the Interface reference from the TMySubscribingObject instance, confused Delphi into always giving me the same Interface reference.<\/p>\n<p>Drop the GUID and drop the \u201cas\u201d, and it all worked beautifully.<\/p>\n<p>In future posts I\u2019ll show the other side of the equation, the Publisher, as well as the Event Broker in the middle. One other nice side-effect of indicating the events a class is interested in, using interfaces in this way, is that the event broker can simply inspect the interfaces implemented by a subscriber to know which events they are interested in subscribing to.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Most of the examples I\u2019ve seen of Generics in Delphi, use classes containing a generic type. However, while working on a personal project, I decided I wanted an Interface containing a generic type. The project uses an in-process publish\/subscribe mechanism, and I wanted a subscriber to have a separate Receive method for each event type, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[97,98],"tags":[19,48,20,51,47],"class_list":["post-420","post","type-post","status-publish","format-standard","hentry","category-architecture","category-coding","tag-delphi","tag-embarcadero","tag-generics","tag-interfaces","tag-publish-and-subscribe"],"_links":{"self":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/420","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=420"}],"version-history":[{"count":24,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/420\/revisions"}],"predecessor-version":[{"id":1760,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/420\/revisions\/1760"}],"wp:attachment":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=420"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=420"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=420"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}