Я храню маленькие интерфейсы от диапазона объектов в единственный 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 ..
но я хотел бы сделать что-то похожее с интерфейсным типом, действительно ли это возможно?
Думаю, это может удовлетворить ваши потребности.
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.
Просто используйте Поддержки, например:
var
oMTIntf: IMeasureTemperature;
...
If Supports(FList[I], IMeasureTemperature, oMTIntf) then ..
Вы можете использовать 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;