9

I have these interface declarations:

IListener = interface
  procedure HandleEvent(AEvent: TMyEvent);
end;

IExtendedListener = interface(IListener)
  ['{85A3456A-D5E5-4F37-ABDD-A75A7B3B494C}']  // required by GetInterface
  procedure HandleExtendedEvent(AExtendedEvent: TMyExtendedEvent);
end;

Given an interface reference for something that implements IListener, how can I check whether it also implements IExtendedListener? I'm using the code below code because it is a compile time error to do something like if Listener is IExtendedListener then ....

TSomeClass.Notify(AEvent: TMyExtendedEvent);
var
  Listener: IListener;
  ExtListener: IExtendedListener;
  Obj: TObject;
begin
  for Listener in FListeners do
  begin
    // works but smells funny
    Obj := Listener as TObject;
    Obj.GetInterface(IExtendedListener, ExtListener);
    if Assigned(ExtListener) then
      ExtNotifyee.HandleExtendedEvent(AEvent);
  end;
end;
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Lawrence Barsanti
  • 31,929
  • 10
  • 46
  • 68
  • 2
    have a look at http://docwiki.embarcadero.com/Libraries/XE3/en/System.SysUtils.Supports – Sir Rufo Jan 15 '13 at 16:38
  • 1
    Your code does not check whether IExtendedListener inherits from IListener, merely that the instance referenced through IListener also supports IExtendedListener. It in no way says anything about inheritance between the two interfaces. – Marjan Venema Jan 15 '13 at 16:43
  • `HandleExtendedEvent` has got only one argument in declaration. Why do you want to pass 2 arguments? – Sir Rufo Jan 15 '13 at 16:47
  • Doesn't checking for a specific "Level" of inheritance defeats the whole purpose of inheriting? – ESG Jan 15 '13 at 16:47
  • 1
    @MarjanVenema, I asked the question because 'if Listener is IExtendedListener then' will not compile. – Lawrence Barsanti Jan 15 '13 at 16:49
  • That's fine, just wanted to make sure that you and anybody reading this understand that the code doesn't say anything about inheritance to avoid any possible confusion. Supports is the easiest way to check and get the proper reference. And you need to get a reference specific to the exact interface because interface references cannot be "hard" cast'ed as object references can. Interface inheritance is a whole different ball game from class inheritance. – Marjan Venema Jan 15 '13 at 16:54
  • From the top of my head (can't check right now, one of my VM servers crashed, so no Delphi VMs at hand), when both interfaces have a GUID, you can use the `is` construct that @MarjanVenema referred to. Hopefully the VM server gets resurrected soon. You might also want to read this one: http://stackoverflow.com/questions/2992183/are-guids-necessary-to-use-interfaces-in-delphi If anyone can check this sooner than I can, please do. – Jeroen Wiert Pluimers Jan 15 '13 at 20:04
  • 1
    @JeroenWiertPluimers, I believe you are mistaken. I added a guid to TListener but couldn't use `is`. It would be nice though. – Lawrence Barsanti Jan 16 '13 at 01:15
  • @LawrenceBarsanti thanks for verifying that. – Jeroen Wiert Pluimers Jan 16 '13 at 08:07

1 Answers1

21

You should use Sysutils.Supports to check for a special Interface

uses
  SysUtils;

TSomeClass.Notify(AEvent: TMyExtendedEvent);
var
  Listener    : IListener;
  ExtListener : IExtendedListener;
begin
  for Listener in FListeners do
    if Supports( Listener, IExtendedListener, ExtListener ) then
      ExtListener.HandleExtendedEvent( AEvent );
end;
Lawrence Barsanti
  • 31,929
  • 10
  • 46
  • 68
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
  • I was cleaning up the code for the question and left the reference to self in. – Lawrence Barsanti Jan 15 '13 at 16:47
  • @LawrenceBarsanti ok, that make sense to me and did not affect the question :o) – Sir Rufo Jan 15 '13 at 16:48
  • Probably they did it like that as optimization, but they should still have supported "is" and "as" for interfaces too. They could have check in the compiler if they could optimize "as" followed by "is" with some caching internally of the result of the interface "cast" (done during checking, guess that was needed for COM interfaces) – George Birbilis Nov 26 '21 at 08:33