简体   繁体   English

在泛型类中转换为接口delphi

[英]Casting in generic class to interface delphi

I'm getting a IEnumVariant from a .NET class library and I am trying to use a generic class to convert this to a IEnumerator 我从.NET类库中获取IEnumVariant,我试图使用泛型类将其转换为IEnumerator

There is a compiler error, "Operator not applicable to this operand type" when attempting to cast an IInterface to the generic type T I've seen workarounds when attempting to type cast to a class, but these don't work for an interface. 尝试将II接口转换为泛型类型时,存在编译器错误“运算符不适用于此操作数类型”我尝试将类型转换为类时遇到过变通方法,但这些不适用于接口。

Using Supports as suggested by Rob seems to have problems as well as TypeInfo returns nil for the parameterized type. 使用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;

Am I missing something in order to get that case to the generic interface type to work ? 我是否遗漏了一些东西,以便使通用接口类型的情况起作用?

I do have the alternative constructor which I CAN get the guid from so that 我确实有替代构造函数,我可以从中获取guid

TDotNetEnum<IContact>.Create(vContactList, IContact);

works but the ideal 工作但理想

TDotNetEnum<IContact>.Create(vContactList); 

doesn't

Using as to cast interfaces is only valid for interfaces that have GUIDs. 使用as转换接口仅对具有GUID的接口有效。 The compiler cannot assume that T has a GUID when it's compiling your generic class, so it cannot accept an expression of the form val as T . 编译器在编译泛型类时不能假定T具有GUID,因此它不能接受val as T形式val as T的表达式。

This has been covered before, but in reference to the Supports function , which has the same limitation as the as operator. 之前已经介绍过,但是参考了Supports函数 ,它与as运算符具有相同的限制。

The solution is to use RTTI to fetch the interface's GUID, and then use that to type-cast the interface value. 解决方案是使用RTTI获取接口的GUID,然后使用它来输入接口值。 You could use Supports : 你可以使用Supports

guid := GetTypeData(TypeInfo(T))^.Guid;
success := Supports(IUnknown(rgvar), guid, FCurrent);
Assert(success);

You could also call QueryInterface directly: 您也可以直接调用QueryInterface

guid := GetTypeData(TypeInfo(T))^.Guid;
OleCheck(IUnknown(rgvar).QueryInterface(guid, FCurrent));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM