在泛型类中转换为接口delphi

Cli*_*ood 3 delphi generics delphi-xe6

我从.NET类库中获取IEnumVariant,我试图使用泛型类将其转换为IEnumerator

尝试将II接口转换为泛型类型时,存在编译器错误"运算符不适用于此操作数类型"我尝试将类型转换为类时遇到过变通方法,但这些不适用于接口.

使用Rob建议的Supports似乎有问题,TypeInfo为参数化类型返回nil.

uses WinApi.ActiveX, Generics.Collections;

type
  TDotNetEnum<T: IInterface> = class(TInterfacedObject, IEnumerator<T>)
  strict private
    FDotNetEnum: IEnumVariant;
    FCurrent: T;
    function MoveNext: Boolean;
    procedure Reset;
    function GetCurrent: TObject;
    function IEnumerator<T>.GetCurrent = GenericGetCurrent;
    function GenericGetCurrent: T;
  public
    constructor Create(const ADotNetObject: OleVariant);

    //// I can get it to work using this constructor
    // constructor Create(const ADotNetObject: OleVariant; const AGUID: TGUID);
  end;

implementation

uses System.Rtti, SysUtils, mscorlib_TLB, ComObj;

constructor TDotNetEnum<T>.Create(const ADotNetObject: OleVariant);
var
  netEnum: IEnumerable;
begin
  netEnum := IUnknown(ADotNetObject) as mscorlib_TLB.IEnumerable;
  FDotNetEnum := netEnum.GetEnumerator();
end;

function TDotNetEnum<T>.GenericGetCurrent: T;
begin
  result := FCurrent;
end;

function TDotNetEnum<T>.GetCurrent: TObject;
begin
  result := nil;
end;

function TDotNetEnum<T>.MoveNext: Boolean;
var
  rgvar: OleVariant;
  fetched: Cardinal;
  ti: TypeInfo;
  guid: TGUID;
begin
  OleCheck(FDotNetEnum.Next(1, rgvar, fetched));
  result := fetched = 1;
  if not result then
    FCurrent := nil
  else
  begin
    FCurrent := IUnknown(rgvar) as T; // <-- Compiler error here
    //// Doesn't work using Supports either
    // ti := TypeInfo(T);  // <-- returns nil
    // guid := GetTypeData(@ti)^.Guid;
    // Supports(IUnknown(rgvar), guid, FCurrent);
  end;
end;

procedure TDotNetEnum<T>.Reset;
begin
  OleCheck(FDotNetEnum.Reset);
end;
Run Code Online (Sandbox Code Playgroud)

我是否遗漏了一些东西,以便使通用接口类型的情况起作用?

我确实有替代构造函数,我可以从中获取guid

TDotNetEnum<IContact>.Create(vContactList, IContact);
Run Code Online (Sandbox Code Playgroud)

工作但理想

TDotNetEnum<IContact>.Create(vContactList); 
Run Code Online (Sandbox Code Playgroud)

Rob*_*edy 6

使用as转换接口仅对具有GUID的接口有效.编译器T在编译泛型类时不能假定它具有GUID,因此它不能接受表单的表达式val as T.

之前已经介绍过,但是参考Supports了与as操作员具有相同限制功能.

解决方案是使用RTTI获取接口的GUID,然后使用它来输入接口值.你可以使用Supports:

guid := GetTypeData(TypeInfo(T))^.Guid;
success := Supports(IUnknown(rgvar), guid, FCurrent);
Assert(success);
Run Code Online (Sandbox Code Playgroud)

你也可以QueryInterface直接打电话:

guid := GetTypeData(TypeInfo(T))^.Guid;
OleCheck(IUnknown(rgvar).QueryInterface(guid, FCurrent));
Run Code Online (Sandbox Code Playgroud)