【问题标题】:How to store and locate multiple interface types within a Delphi TInterfaceList如何在 Delphi TInterfaceList 中存储和定位多个接口类型
【发布时间】:2010-06-02 15:32:19
【问题描述】:

我将来自一系列对象的小接口存储到单个 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 ..

但我想做一些与接口类型类似的事情,这可能吗?

【问题讨论】:

  • 您可能想澄清您的第一个列表是否包含实际接口types 或对实现这些接口的对象instances 的引用。到目前为止,似乎所有在这里回答的人都假设后者,而我读到你的问题来谈论前者......然后你又不能将接口 types 存储在TInterfaceList......所以我可能错了……

标签: delphi interface


【解决方案1】:

只需使用 Supports,如下所示:

var
  oMTIntf: IMeasureTemperature;
...
  If Supports(FList[I], IMeasureTemperature, oMTIntf) then .. 

【讨论】:

  • @da-soft:很好的建议,但是当单个类导出两个不同的接口时它会失败 - 在这种情况下,“支持”对每个接口都返回 true。我需要一些方法来识别接口的实际类型。
  • 对不起,我好像错过了你的重点。您需要从接口获取对象,还是从接口获取接口?如果是第一个,那么malcolmgroves.com/blog/?p=500。如果是第二个,那么就像我写的那样(我已经编辑了我的消息)。
  • @Brian:为什么这是个问题?如果两个接口之一从另一个继承,则在父类之前检查后代类。如果他们不这样做,那么两个结果同样有效。
  • Err... 在父 interface 之前检查后代 interface 我的意思是。
  • @Brian:如果您正在使用接口,那么具体类是否实现这两个接口都无关紧要。如果它确实重要,那可能是设计缺陷的迹象。
【解决方案2】:

我想这可能会满足您的需求。

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 相互继承时该函数的行为如何,但如果 Intf 与 ExpectedIntf 完全匹配,这将返回 TRUE。

在您的示例中,IMeasureHumidity 不会在 IMeasureTemperature 上返回 true,但我不确定它会如何对 IBase 做出反应。根据初步测试,在IBase上也会返回FALSE。

【讨论】:

  • 除非ExpectedIntfIUnknown,否则不能保证Intf 将永远等于vReferencerules for implementing QueryInterface 承诺调用 QueryInterface 将成功,但它们不需要返回任何特定的接口指针。
  • 来自您自己的链接“使用 IID_IUnknown 调用 QueryInterface 必须始终返回相同的物理指针值”和“任何接口都必须能够查询对象上的任何其他接口”。我不确定您引用的哪个规则会导致此失败。
  • 这工作正常并且完全符合我的期望,尽管我需要非常努力地查看它以了解它在做什么!永远不会有继承的 IBase 接口会被传递的情况。非常感谢。
【解决方案3】:

您可以在 SysUtils 中使用 Supports 函数,它们非常安全(除非您在未初始化的内存上尝试它们)并且您只需要一个您尝试转换为的确切接口类型的目标变量:


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; 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    相关资源
    最近更新 更多