【发布时间】:2021-03-02 20:27:12
【问题描述】:
这对我来说有点令人费解,因为我正在开发一个具有几十个接口的单元,这些接口都基于这个基本接口定义:
type
IDataObject = interface(IInterface)
['{B1B3A532-0E7D-4D4A-8BDC-FD652BFC96B9}']
function This: TDataObject;
end;
ISomeObject = interface(IDataObject)
['{7FFA91DE-EF15-4220-A43F-2C53CBF1077D}']
<Blah>
end;
这意味着他们都有一个方法“This”,它返回接口后面的类,有时需要放入列表视图和其他东西,但对于这个问题,这并不重要,因为我想要一个带有额外的泛型类可以应用于任何派生接口的函数。 (并且任何派生接口都有自己的 GUID。)这是泛型类:
type
Cast<T: IDataObject> = class(TDataObject)
class function Has(Data: IDataObject): Boolean;
class function Get(Data: IDataObject): T;
end;
看起来不太复杂,使用类方法是因为Delphi不支持全局泛型函数,除非它们在一个类中。所以在我的代码中我想使用Cast<ISomeObject>.Has(SomeObject) 来检查对象是否支持特定的接口。 Get() 函数只是将对象作为特定类型返回,如果可能的话。所以,接下来的实现:
class function Cast<T>.Get(Data: IDataObject): T;
begin
if (Data.QueryInterface(T, Result) <> S_OK) then
Result := nil;
end;
class function Cast<T>.Has(Data: IDataObject): Boolean;
begin
Result := (Data.QueryInterface(T, Result) = S_OK);
end;
这就是令人讨厌的地方!在我的代码的其他地方,我使用if (Source.QueryInterface(ISomeObject, SomeObject) = 0) then ...,它工作得很好。在这些通用方法中,ISomeObject 被 T 替换,并且应该可以正常工作。但它拒绝编译并给出这个错误:
[dcc64 错误] DataInterfaces.pas(684): E2010 不兼容的类型: “TGUID”和“T”
这很烦人。我需要解决这个问题,但如果不深入研究系统单元的接口代码,就找不到合适的解决方案。 (这是我允许在此代码中使用的唯一单元,因为它需要在许多不同的平台上运行!)
该错误是正确的,因为 QueryInterface 需要 TGUID 作为参数,但它似乎是从 ISomeObject 获得的。那么为什么不来自 T 呢?
我想我在这里尝试做不可能的事情......
更具体一点:Source.QueryInterface(ISomeObject, SomeObject) 可以在不使用任何其他单元的情况下正常工作。因此,如果该类型仅限于接口,我希望它可以与泛型类型一起使用。但事实并非如此,我想知道为什么它在接受 ISomeObject 时不接受 T。
你能解释一下为什么它会因为泛型类型而不是常规接口类型而失败吗?
【问题讨论】:
-
注意:只允许使用系统单元!这是一个严重的限制......
-
我知道您说您只能使用
System单元,因为您需要跨平台,但您可能是指System命名空间。在这种情况下,傻瓜中基于 RTTI 的解决方案可能是你能做的最好的。 -
@WimtenBrink 泛型并不像人们期望的那样灵活。很多时候,您最终需要使用黑客来解决其中的限制。我建议您将 report this issue to Embarcadero 作为编译器错误。
-
“问题是这个单元一旦准备好就会由其他开发人员维护。”所以呢。定义规则。让他们清楚。监督这些开发商。 “而使用接口的原因是因为他们经常忘记释放对象,而接口通常会释放自己。”教他们。如果他们学不到这一点,那就让他们走吧。如果他们不能学习这一点,那么他们将不会产生任何具有持久价值的东西。实际上,问题不在于初级开发人员缺乏经验,而在于领导力薄弱。
标签: delphi interface delphi-10.4-sydney