11

我有以下代码

IProxy<T> = interface
  ['{1E3A98C5-78BA-4D65-A4BA-B6992B8B4783}']
  function Setup : ISetup<T>;
  function Proxy : T;
  function CastAs<I : IInterface> : IInterface;
end;

有没有办法解决编译时收到的编译器错误?

“[DCC 错误] Delphi.Mocks.pas(123): E2535 接口方法不能有参数化方法”

基本上,我希望通过传入要转换为的类型并返回该类型来传递此接口并能够将其丢弃。我可以通过一个类来实现这一点,但是更喜欢传递一个接口。

附加信息:

说我有以下课程

TInterfaceProxy<T> = class(TBaseProxy<T>)
private type
  TProxyVirtualInterface = class(TVirtualInterface)
  private
    FProxy : TInterfaceProxy<T>;
  protected
  public
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; override; stdcall;
    constructor Create(AProxy : TInterfaceProxy<T>; AInterface: Pointer; InvokeEvent: TVirtualInterfaceInvokeEvent);
  end;
private
  FVirtualInterfaces : TDictionary<TGUID, TProxyVirtualInterface>;
protected
  function InternalQueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
  function QueryInterface(const IID: TGUID; out Obj): HRESULT; override;
  function Proxy : T;override;
  function CastAs<I: IInterface> : I;
public
  constructor Create;override;
  destructor Destroy;override;
end;

CastAs 在这里工作得很好,因为新请求的演员可以创建一个新的虚拟接口。现在,如果我想通过这门课就可以了。但是,如果我需要它作为接口,即TInterfaceProxy<T> = class(TBaseProxy<T>, IProxy<T>)它不起作用,请理解这一点。不同意,但理解。

因此,我如何绕过这个限制,以便我可以调用 CastAs 函数,传入一个类型(任何开始的接口类型),并能够从中创建一个虚拟接口?

4

3 回答 3

17

正如编译器所说,接口不支持泛型参数化方法。

没有解决方法,因为它是一个基本限制。类中的参数化方法是通过向类中的每个实例添加一个方法来实现的。这适用于类,因为它们是具体的,但不适用于接口。这是因为接口是一个函数表,并且该表的大小不能根据代码中其他地方碰巧出现的泛型方法实例而变化。出于类似的原因,泛型方法不能是虚拟的或动态的。

您问题中的代码也有点误导。你写了:

function CastAs<I : IInterface> : IInterface;

但我确定你的意思是:

function CastAs<I : IInterface> : I;

无论如何,这是不可能的。一种选择是改用一个类。我同意这是一个绑定。

如果您想在界面中执行此操作,您可以做的最好的事情是:

function CastAs(const IID: TGUID): IInterface;

但是你必须这样称呼它:

MyIntf := ProxyIntf.CastAs(IMyIntf) as IMyIntf;

感觉有点犯规。

选择你的毒药!

于 2013-05-14T04:32:33.513 回答
7

如错误消息所述,接口中的方法不能具有通用参数。编译器根本不支持它,这是这样记录的:

http://docwiki.embarcadero.com/RADStudio/XE4/en/Overview_of_Generics

接口中的参数化方法

不能在接口中声明参数化方法(使用类型参数声明的方法)。

换句话说,您的CastAs方法是非法的,因为它是在接口类型中声明的。另一方面,您一开始就不需要这种方法。您可以SysUtils.Supports()改为使用将一个接口转换为另一个接口。

于 2013-05-14T01:20:14.233 回答
1

使用 Delphi 11.0 为我编译了类似以下内容(尚未查看它是否崩溃):

TStoryItemList = TList<IStoryItem>;

TObjectListEx<T: class> = class
    class function GetAllOfInterface<AInterface: IInterface>(const list: TList<T>): TList<AInterface>;
  end;

//...

class function TObjectListEx<T>.GetAllOfInterface<AInterface>(const list: TList<T>): TList<AInterface>;
var
  itemAsAInterface: AInterface;
begin
  var guid := TRttiInterfaceType(TRttiContext.Create.GetType(TypeInfo(AInterface))).GUID;
  var listOfAInterface := TList<AInterface>.Create;
  for var item in list do
    if Supports(item, guid, itemAsAInterface) then
      listOfAInterface.Add(itemAsAInterface);
  result := listOfAInterface;
end;

用法

function TStoryItem.GetStoryItems: TStoryItemList;
begin
  result := TObjectListEx<TControl>.GetAllOfInterface<IStoryItem>(Controls);
end;
于 2021-10-18T15:53:05.967 回答