gpt4 book ai didi

Delphi - 无法将 TVirtualInterface 转换为虚拟化接口(interface)的基接口(interface)

转载 作者:行者123 更新时间:2023-12-01 17:56:10 25 4
gpt4 key购买 nike

豪迪,

我正在使用 TVirtualInterface 来实现一些接口(interface)。这些接口(interface)代表可以在数据库中找到的键。我使用定制的代码生成器生成接口(interface)定义。例如:

// Base code 

IKey = interface
function KeyFields : string;
function KeyValues : Variant;
function GetKeyValue(const aKeyName : string) : Variant;
procedure SetKeyValue(const aKeyName : string; Value : Variant);
end;

// Generated code

ITable1Key = interface(IKey)
end;

ITable1Key1 = interface(ITable1Key)
procedure SetField1(const Value : string);
function GetField1 : string;
property Field1 : string read GetField1 write SetField1;
end;

ITable1Key2 = interface(ITable1Key)
procedure SetField1(const Value : string);
function GetField1 : string;
property Field1 : string read GetField1 write SetField1;
procedure SetField2(const Value : string);
function GetField2 : string;
property Field2 : string read GetField1 write SetField1;
end;

// Other generated declarations

我使用TVirtualInterface来实现每个IKey接口(interface),而不是一一实现。

不过,在我的 TVirtualInterface 中:

TKey = TVirtualInterface
public
constructor Create(aType : PTypeInfo);
function Cast : IKey;
end;

TKey<T : IKey>
public
constructor Create; reintroduce;
function Cast : T;
end;


constructor TKey.Create(aType : PTypeInfo)
begin
inherited Create(aType, aHandlerMethod);
end;

function TKey.Cast;
var
pInfo: PTypeInfo;
begin
pInfo := TypeInfo(IKey);
if QueryInterface(GetTypeData(pInfo).Guid, Result) <> 0 then
begin
raise Exception.CreateFmt('Sorry, TKey is unable to cast %s to its interface ', [string(pInfo.Name)]);
end;
end;

constructor TKey<T>.Create;
begin
inherited Create(TypeInfo(T));
end;

function TKey<T>.Cast;
var
pInfo: PTypeInfo;
begin
pInfo := TypeInfo(T);
if QueryInterface(GetTypeData(pInfo).Guid, Result) <> 0 then
begin
raise Exception.CreateFmt('Sorry, TKey<T> is unable to cast %s to its interface ', [string(pInfo.Name)]);
end;
end;

使用 TKey.Cast 方法将 TKey 虚拟接口(interface)转换为 T 类型没有问题,但 TKey.Cast 返回接口(interface)不支持错误。

我在 System.Rtti 中检查了未按我希望的方式工作的部分:

function TVirtualInterface.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if iid = FIID then
begin
_AddRef;
Pointer(Obj) := @VTable;
Result := S_OK;
end
else
Result := inherited
end;

现在,如何强制 TVirtualInterface 将自身转换为作为 FIID 字段的父接口(interface)的 IID?我是否必须为 IKey 接口(interface)创建另一个 TVirtualInterface 实例?

非常感谢。

最佳答案

您滥用了 TVirtualInterface 。它只是一个 RTTI 助手,您根本不应该从它派生。您应该源自 TInterfacedObject相反。

此外,您的 TKey类忽略 PTypeInfo传递给构造函数。非通用TKey.Cast()总是查询IKey只是,绝不是后代接口(interface)。和通用TKey<T>.Cast总是重新查询T的 RTTI 来获取其 IID。所以摆脱PTypeInfo在构造函数中,它被浪费了。

自非泛型TKey只是一个基类,实际上根本没有实现任何派生接口(interface),TKey.QueryInterface()IKey 之外的任何接口(interface)都将始终失败本身。至少通用TKey可以查询派生接口(interface)。

您的Cast无论如何,函数都是多余的,因为您可以使用 as运算符,或 SysUtils.Supports()函数,将一个接口(interface)转换为另一个接口(interface)。这些是首选方法,不使用 QueryInterface()手动。

无论如何,您的接口(interface)在其声明中都缺少 IID,因此无论如何您都无法在接口(interface)之间进行转换。

尝试更多类似这样的事情:

// Base code 

IKey = interface
['{D6D212E0-C173-468C-8267-962CFC3FECF5}']
function KeyFields : string;
function KeyValues : Variant;
function GetKeyValue(const aKeyName : string) : Variant;
procedure SetKeyValue(const aKeyName : string; Value : Variant);
end;

// Generated code

ITable1Key = interface(IKey)
['{B8E44C43-7248-442C-AE1B-6B9E426372C1}']
end;

ITable1Key1 = interface(ITable1Key)
['{0C86ECAA-A8E7-49EB-834F-77DE62BE1D28}']
procedure SetField1(const Value : string);
function GetField1 : string;
property Field1 : string read GetField1 write SetField1;
end;

ITable1Key2 = interface(ITable1Key)
['{82226DE9-221C-4268-B971-CD72617C19C7}']
procedure SetField1(const Value : string);
function GetField1 : string;
property Field1 : string read GetField1 write SetField1;
procedure SetField2(const Value : string);
function GetField2 : string;
property Field2 : string read GetField1 write SetField1;
end;

// Other generated declarations

type
TKey = class(TInterfacedObject, IKey)
public
function Cast : IKey;
// IKey methods...
end;

TKey<T : IKey> = class(TInterfacedObject, IKey, T)
public
function Cast : T;
end;

TTable1Key = class(TKey, IKey, ITable1Key)
end;

TTable1Key1 = class(TTable1Key, IKey, ITable1Key, ITable1Key1)
public
// ITable1Key1 methods...
end;

TTable1Key2 = class(TTable1Key, IKey, ITable1Key, ITable1Key2)
public
// Table1Key2 methods...
end;

// and so on ...

function TKey.Cast: IKey;
begin
if not Supports(Self, IKey, Result) then
raise Exception.Create('Sorry, unable to cast to IKey');
end;

function TKey<T>.Cast: T;
begin
if not Supports(Self, GetTypeData(TypeInfo(T)).Guid, Result) then
raise Exception.CreateFmt('Sorry, unable to cast to %s', [string(TypeInfo(T).Name)]);
end;

// other class methods as needed ...

还要注意派生类如何必须重复其基类实现的接口(interface)。这是德尔福已知的限制。派生类不继承基类接口(interface)。每个类都必须显式指定它实现的接口(interface),即使实际实现位于基类中。

关于Delphi - 无法将 TVirtualInterface 转换为虚拟化接口(interface)的基接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44574125/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com