【问题标题】:Delphi: how to access an object's base class methods from an interface type variableDelphi:如何从接口类型变量访问对象的基类方法
【发布时间】:2019-07-24 11:08:43
【问题描述】:

...反之亦然。假设我无法控制两个类,它们都继承自同一个基类:

TDataSet1 = class(TDataSet)
...
end;

TDataSet2 = class(TDataSet)
...
end;

我有一个这样的接口声明:

IMyDataSet = interface
  procedure MyProc;
end;

然后我有两个类继承了之前的类并实现了我的接口:

TMyDataSet1 = class(TDataSet1, IMyDataSet)
  procedure MyProc;
end;

TMyDataSet2 = class(TDataSet2, IMyDataSet)
  procedure MyProc;
end;

现在我的问题是:我有一堆过程和函数,它们必须接受一个对象作为参数,该对象可以是我的两个类的实例。 我不需要访问特定于我的两个类或祖先类的属性或方法,只需要访问基类TDataSet 在接口IMyDataSet 中声明的那些。

如果我这样声明一个过程:

procedure Foo(ADataSet: TDataSet);

我只能调用来自TDataSet 类的方法。

如果我以这种方式声明过程:

procedure Foo(ADataSet: IMyDataSet);

我只能看到属于该接口的方法。

有什么方法可以让我在传递给程序的引用上看到TDataSetIMyDataSet 方法

【问题讨论】:

    标签: delphi interface


    【解决方案1】:

    您可以将参数声明为接口,然后将其类型转换为方法内的对象引用。 (这种类型转换适用于 Delphi 2010 及更高版本)

    procedure Foo(ADataSet: IMyDataSet);
    var
      LDataSet: TDataSet;
    begin
      LDataSet := TDataSet(ADataSet);
      ... 
    end;
    

    注意:如果IMyDataSet 接口未在TDataSet 上实现,则上述类型转换将失败而不会引发异常并返回nil

    您也可以使用as 运算符进行类型转换,但在这种情况下,失败会引发异常。

    LDataSet := ADataSet as TDataSet;
    

    另一种选择是将参数作为对象实例传递,然后从对象中检索接口。在这种情况下,您的界面必须有 GUID。

    IMyDataSet = interface
      ['{XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'] // replace with actual GUID
      procedure MyProc;
    end;
    
    procedure Foo(ADataSet: TDataSet);
    var
      LDataSet: IMyDataSet;
    begin
      if Supports(ADataSet, IMyDataSet, LDataSet) then
        begin
          ... 
        end;
    end;
    

    【讨论】:

    • 我认为您的第一个答案可能不适用于我的情况,TDataSet 肯定没有实现 IMyDataSet(我的示例非常接近实际情况,TDataSet 正是 Delphi 的本机 TDataSet 类)。实际上,我的两个类都实现了 IMyDataSet,但这足以让类型转换工作吗?第二个答案似乎还可以......我实际上有数百个过程和函数,我必须将这些对象传递给它们,所以也许我可以创建一个函数来支持支持的事情并返回接口引用,它会工作吗?
    • 如果我理解正确,实现 IMyDataset 的 TDataSet1 继承自 TDataSet (这就是你写的),第一个答案将起作用。如果不是这种情况,那么第二个答案也不起作用。
    • 实际上是 TMyDataSet1(和 2)实现了 IMyDataSet,而在 TDataSet1 上我无法控制。无论如何,如果我理解正确,如果我的参数是 IMyDataSet 类型并且我传递了 TMyDataSet1 的实例(实现接口),那么强制转换将起作用,对吗?顺便说一句,第二种方式对我来说似乎更有用,我将编写一个返回 IMyDataSet 的小函数,并仅在我需要从该接口调用方法时使用它,而其余使用 TDataSet 方法的代码保持不变(我' m 对旧代码进行“升级”)。
    • 只要所有类都以 TDataSet 作为祖先,那么在哪个点(类)实际实现接口并不重要。您可以选择这两种方法,具体取决于哪一种更适合您。
    猜你喜欢
    • 2021-05-05
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-02
    相关资源
    最近更新 更多