Как сохранить и определить местоположение нескольких интерфейсных типов в Delphi TInterfaceList

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

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

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

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

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

  If FList[I] is TMeasureTemperature then ..

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

6
задан Brian Frost 2 June 2010 в 15:32
поделиться

3 ответа

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

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 для IMeasureTempera, но я не уверен, как он отреагирует на IBase. Согласно предварительному тестированию, он также вернет FALSE на IBase.

2
ответ дан 10 December 2019 в 00:34
поделиться

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

var
  oMTIntf: IMeasureTemperature;
...
  If Supports(FList[I], IMeasureTemperature, oMTIntf) then .. 
6
ответ дан 10 December 2019 в 00:34
поделиться

Вы можете использовать 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; 
2
ответ дан 10 December 2019 в 00:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: