Как хранить и находить несколько типов интерфейсов в Delphi TInterfaceList - PullRequest
6 голосов
/ 02 июня 2010

Я храню небольшие интерфейсы из ряда объектов в одном «хранилище» TInterfaceList с намерением предложить список определенных типов интерфейсов конечному пользователю, поэтому каждый интерфейс будет предоставлять функцию «GetName», но все другие методы являются уникальными для этого типа интерфейса. Например, вот два интерфейса:

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

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

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

Я поместил несколько из этих интерфейсов в один TInterfaceList, а затем я хотел бы отсканировать список для определенного типа интерфейса (например, «IMeasureTempera»), создав еще один список указателей на объекты, экспортирующие эти интерфейсы. Я не хочу делать предположений о расположении этих объектов, некоторые могут экспортировать более одного типа интерфейса. Я знаю, что мог бы сделать это с помощью иерархии классов, используя что-то вроде:

  If FList[I] is TMeasureTemperature then ..

но я бы хотел сделать что-то похожее с типом интерфейса. Возможно ли это?

Ответы [ 3 ]

6 голосов
/ 02 июня 2010

Просто используйте поддержку, как это:

var
  oMTIntf: IMeasureTemperature;
...
  If Supports(FList[I], IMeasureTemperature, oMTIntf) then .. 
2 голосов
/ 02 июня 2010

Я думаю, это может удовлетворить ваши потребности.

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

Я не уверен, как будет вести себя функция, когда Intf и ExpectedIntf наследуются друг от друга, но это вернет TRUE в случае, если Intf является точным соответствием ExpectedIntf.

В вашем примере IMeasureHumidity не вернет true на IMeasureTemperam, но я не уверен, как он отреагирует на IBase. Согласно предварительному тестированию, он также вернет FALSE на IBase.

2 голосов
/ 02 июня 2010

Вы можете использовать функцию Supports в SysUtils, они довольно безопасны (если только вы не пробуете их в унифицированной памяти), и вам нужна только целевая переменная того типа интерфейса, который вы пытаетесь привести:


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; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...