【问题标题】:How to cast one interface to another in Delphi 7?如何在 Delphi 7 中将一个接口转换为另一个接口?
【发布时间】:2023-03-25 18:13:01
【问题描述】:

我遇到了以下问题:

我有一个类,它是使用 Delphi 7 XML 数据绑定向导(新建 -> 其他 -> XML Databindng)从 xsd 文件生成的。

我需要想办法给生成的代码添加方法:

IXMLGlobeSettingsType = interface(IXMLNode)
    ['{9A8F5C55-F593-4C70-85D2-68FB97ABA467}']
    { Property Accessors }
    function Get_General: IXMLGeneralSettingsType;
    function Get_Projector: IXMLProjectorSettingsType;
    function Get_LineMode: IXMLLineDrawingSettingsType;

    { Methods & Properties }
    property General: IXMLGeneralSettingsType read Get_General;
    property Projector: IXMLProjectorSettingsType read Get_Projector;
    property LineMode: IXMLLineDrawingSettingsType read Get_LineMode;

    //procedure SetDefault;   {To be added}
  end;

接口由对应的类实现,也是由向导生成的:

TXMLGlobeSettingsType = class(TXMLNode, IXMLGlobeSettingsType)
  protected
    { IXMLGlobeSettingsType }
    function Get_General: IXMLGeneralSettingsType;
    function Get_Projector: IXMLProjectorSettingsType;
    function Get_LineMode: IXMLLineDrawingSettingsType;
  public
    procedure AfterConstruction; override;
  end;

并且为了定义我自己对生成代码的扩展,我定义了以下接口:

IDefaultable = interface
   procedure SetDefault;
end;

具有以下实现类:

DefaultableXMLGlobeSettingsType = class(TXMLGlobeSettingsType, IDefaultable)
  public
    procedure SetDefault;
  end;

然而,我刚刚意识到 Delphi 7 不允许我将一个接口转换为另一个接口(甚至从一个接口转换为一个对象)。所以下面的代码会报错:

defaultSettings : IDefaultable;    
FGlobeSettingsIntf: IXMLGlobeSettingsType; // FGlobeSettingsIntf is in fact a DefaultableXMLGlobeSettingsType

// some code

defaultSettings := FGlobeSettingsIntf as IDefaultable; // error: operator not applicable to this operand type

我几乎被困在这里。如何绕过这个错误?在 Delphi 7 中有没有办法(甚至是丑陋的)将接口转换为一个对象,然后再转换回另一个接口。

【问题讨论】:

  • OK 接受了你的(抱歉 Uwe!)。
  • 没关系!大卫是对的——没有什么好争论的。

标签: delphi delphi-7


【解决方案1】:
defaultSettings := FGlobeSettingsIntf as IDefaultable;
// error: operator not applicable to this operand type

此错误表明IDefaultable 的定义不包含 GUID。如果没有 GUID,就无法查询接口,这就是 as 运算符在此上下文中所做的。

as 运算符在与右侧的接口一起使用时,通过调用 IInterface.QueryInterface 来实现。这需要一个 GUID 与接口相关联。

通过在声明 IDefaultable 时添加 GUID 来解决问题。

【讨论】:

  • 提示:在编辑器中使用 Ctrl+Shift+G 计算并在接口类型第一行下方插入一个新的唯一 GUID。
  • @David Heffernan 为了完整起见接受您的回答。 Uwe的回答也很有用。谢谢 Uwe!
  • 实际上,可以实现 QueryInterface 以返回任何可以以某种方式与 GUID 关联的接口。自定义 QueryInterface 可以通过内置方式以外的其他方式将接口与 GUID 相关联。通常(和内置)方式是您所描述的,但它的工作方式可能完全不同,然后不必像在 Delphi 中通常那样为接口定义 GUID。不过,我不知道为什么有人会以不同的方式做这件事,但这不是我的意思。
  • @Rudy 坚持手头的问题,as 将通过与接口关联的 GUID 导致对 QI 的调用。因此,实际上,在不更改使用as 的代码的情况下解决错误的唯一方法是在界面中添加一个 GUID。
【解决方案2】:

这就是Supports 的用途:

if Supports(FGlobeSettingsIntf, IDefaultable, defaultSettings) then begin
  defaultSettings.SetDefault;
end;

【讨论】:

  • 非常感谢您的回答。接受它是因为它似乎是从接口转换到另一个接口的干净方式,尽管我的代码未编译的主要原因是缺少 GUID(请参阅原始问题的编辑)。但是我不清楚支持的签名:function Supports(const Instance: IInterface; const IID: TGUID; out Intf): Boolean; 第二个参数是TGUID。就我而言,它是IDefaultable。我错过了什么吗?
  • @BigONotation 可以将接口类型传递给 TGUID,编译器将替换接口的实际 guid
  • @RemyLebeau 非常感谢您的澄清!这些统计数据是有道理的。
猜你喜欢
  • 1970-01-01
  • 2023-01-28
  • 2012-05-12
  • 2019-05-08
  • 2021-07-22
  • 2011-03-31
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
相关资源
最近更新 更多