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)
不
使用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)