Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store and locate multiple interface types within a Delphi TInterfaceList

I'm storing small interfaces from a range of objects into a single TInterfaceList 'store' with the intention of offering list of specific interface types to the end user, so each interface will expose a 'GetName' function but all other methods are unique to that interface type. For example here are two interfaces:

  IBase = interface
    //----------------------------------------
    function GetName : string;
    //----------------------------------------
  end;

  IMeasureTemperature = interface(IBase)
    //------------------------------------
    function MeasureTemperature : double;
    //----------------------------------------
  end;

  IMeasureHumidity = interface(IBase)
    //----------------------------------------
    function MeasureHumidity: double;
    //----------------------------------------
  end;

I put several of these interfaces into a single TInterfaceList and then I'd like to scan the list for a specific interface type (e.g. 'IMeasureTemperature') building another list of pointers to the objects exporting those interfaces. I wish to make no assumptions about the locations of those objects, some may export more than one type of interface. I know I could do this with a class hierarchy using something like:

  If FList[I] is TMeasureTemperature then ..

but I'd like to do something simliar with an interface type, Is this possible?

like image 908
Brian Frost Avatar asked Jun 02 '10 15:06

Brian Frost


3 Answers

Just use Supports, like this:

var
  oMTIntf: IMeasureTemperature;
...
  If Supports(FList[I], IMeasureTemperature, oMTIntf) then .. 
like image 170
da-soft Avatar answered Sep 19 '22 05:09

da-soft


I guess that might satisfy your needs.

function InterfaceRefIsInterface(Intf : IUnknown; ExpectedIntf : TGUID) : Boolean;
var vReference : IUnknown;
begin
  if Supports(Intf, ExpectedIntf, vReference)  then
    Result := Intf = vReference
  else
    Result := False;
end;

I'm not sure how the function will behave when Intf and ExpectedIntf inherits from one another, but this will return TRUE in the case Intf is an exact match of ExpectedIntf.

In your exemple, IMeasureHumidity won't return true on IMeasureTemperature, but I'm not sure how it will react to IBase. According to preliminary testing, it will also return FALSE on IBase.

like image 24
Ken Bourassa Avatar answered Sep 18 '22 05:09

Ken Bourassa


You may use the Supports function in SysUtils, they are pretty safe (unless you try them on unitialized memory) and you only need a target variable of the exact interface type you try to cast to:


procedure DoSomethingInList(AList: IInterfaceList;);
var
  i: Integer;
  liItem: IInterface;
  liMeasureTemp: IMeasureTemperature;
  liMeasureHumi: IMeasureHumidity;
begin
  AList.Lock;
  try
    for i := 0 to AList.Count - 1 do
    begin
      liItem := AList[i];
      if Supports(liItem, IMeasureTemperature, liMeasureTemp) then
        //... liMeasureTemp.MeasureTemperature ...
      else if Supports(liItem, IMeasureHumidity, liMeasureHumi) then
        //... liMeasureHumi.MeasureHumidity ...
      else 
        //...
    end;
  finally
    AList.Unlock;
  end;
end; 
like image 43
Viktor Svub Avatar answered Sep 19 '22 05:09

Viktor Svub