[英]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.