Delphi - 接口继承与泛型 [英] Delphi - Interface inheritance with generics
问题描述
作为代码我正在使用2个接口,继承和2类,继承。
以下代码重现错误:
程序Project22;
{$ APPTYPE CONSOLE}
type
IStorageObject = interface(IInterface)
end;
TObjectStorage< T:IStorageObject> = class(TObject)
end;
IKeyStorageObject< TKey> = interface(IStorageObject)
end;
TKeyObjectStorage< TKey,T:IKeyStorageObject< TKey>> = class(TObjectStorage< T>)
end;
TImplementingClass< TKey> = class(TInterfacedObject,IKeyStorageObject< TKey>)
end;
begin
TKeyObjectStorage< Integer,TImplementingClass< Integer>> .Create;
结束。
'TKeyObjectStorage'的编译器错误是:
[DCC错误] Project22.dpr(11):E2514类型参数'T'必须支持IStorageObject接口
我认为是编译器没有正确地识别Class'TKeyObjectStorage'的参数T。
它应该是正确的,因为想要的类型'IKeyStorageObject'具有父类型IStorageObject。
为什么这不起作用?我究竟做错了什么?这是不可能在德尔福?
更新
原来的问题有一个我确定的问题(见下文)。但是,我描述的修复对于XE3和更高版本是很好的,但下面的程序不能在XE2中编译。因此,我得出结论,这是一个XE2泛型编译器错误。
无论如何,以下是 Delphi XE2 的解决方法:
{$ APPTYPE CONSOLE}
type
IStorageObject = interface(IInterface)
end;
TObjectStorage< T:IStorageObject> = class(TObject)
end;
IKeyStorageObject< TKey> = interface(IStorageObject)
end;
TKeyObjectStorage< TKey; T:IKeyStorageObject< TKey>,IStorageObject> = class(TObjectStorage< T>)
end;
TImplementingClass< TKey> = class(TInterfacedObject,IStorageObject,IKeyStorageObject< TKey>)
end;
begin
TKeyObjectStorage< Integer,TImplementingClass< Integer>> .Create;
结束。
原始答案 / p>
如果您提供了一个展示编译器错误的完整程序,这将会更好。您需要尝试实例化一个对象才能看到该错误。
但是,我想我已经转载了你的问题。所以我相信问题是这个代码:
TKeyObjectStorage< TKey,T:IKeyStorageObject&TK;>> = ...
将通用约束应用于 TKey
和 T
。现在,显然你只希望约束适用于 T
,所以你需要写:
TKeyObjectStorage< TKey; T:IKeyStorageObject< TKey>> = ...
这是一个简短的程序,根据 Delphi XE3 :
{$ APPTYPE CONSOLE}
type
IStorageObject = interface(IInterface)
结束
TObjectStorage< T:IStorageObject> = class(TObject)
end;
IKeyStorageObject< TKey> = interface(IStorageObject)
end;
TKeyObjectStorage< TKey; T:IKeyStorageObject< TKey>> = class(TObjectStorage< T>)
end;
TImplementingClass< TKey> = class(TInterfacedObject,IKeyStorageObject< TKey>)
end;
begin
TKeyObjectStorage< Integer,TImplementingClass< Integer>> .Create;
结束。
这是一个细微差别,将逗号更改为分号。通过重要的标点符号编程从来没有太多的乐趣。那就是说,你熟悉在形式参数列表中的逗号和分号之间的区别,所以它不应该是太多的惊喜,看到这里同样的区别。
文档确实涵盖了这一点:
多个类型参数
指定约束时,可以将多个类型参数分隔
分号,与参数列表声明一样:键入
TFoo< T:ISerializable;五:IComparable>
像参数声明一样,多个类型参数可以通过逗号列表绑定
同样的限制:键入
TFoo< S,U:ISerializable> ...
在上面的例子中,
S
和U
都绑定到ISerializable
约束。
I am currently stuck with a compiling error, no one in our company can help and I am sadly not finding the correct search patterns for SO or google.
As code I am using 2 Interfaces, inherited and 2 Classes, inherited. The following code reproduces the error:
program Project22;
{$APPTYPE CONSOLE}
type
IStorageObject = interface(IInterface)
end;
TObjectStorage<T: IStorageObject> = class(TObject)
end;
IKeyStorageObject<TKey> = interface(IStorageObject)
end;
TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>)
end;
TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>)
end;
begin
TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.
The compiler error for 'TKeyObjectStorage' is:
[DCC Error] Project22.dpr(11): E2514 Type parameter 'T' must support interface 'IStorageObject'
What I think is, that the compiler is not recognizing that Parameter T of the Class 'TKeyObjectStorage' correctly. It should be correct, since the wanted Type 'IKeyStorageObject' has the parent type IStorageObject.
Why is this not working? What am I doing wrong? Is this not possible in Delphi?
Update
The original question had a problem which I identified (see below). However, the fix I describe there is fine for XE3 and later, but that program below does not compile in XE2. Thus I conclude that this is an XE2 generics compiler bug.
Anyway, here's a workaround for Delphi XE2:
{$APPTYPE CONSOLE}
type
IStorageObject = interface(IInterface)
end;
TObjectStorage<T: IStorageObject> = class(TObject)
end;
IKeyStorageObject<TKey> = interface(IStorageObject)
end;
TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>, IStorageObject> = class(TObjectStorage<T>)
end;
TImplementingClass<TKey> = class(TInterfacedObject, IStorageObject, IKeyStorageObject<TKey>)
end;
begin
TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.
Original answer
It would have been better if you had provided a complete program that exhibited the compiler error. You need to attempt to instantiate an object to see that error.
But, I think I've reproduced your problem. So I believe that the issue is that this code:
TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ...
applies the generic constraint to both TKey
and T
. Now, clearly you only want the constraint to apply to T
so you'll need to write:
TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ...
Here's a short program that compiles following the change in Delphi XE3:
{$APPTYPE CONSOLE}
type
IStorageObject = interface(IInterface)
end;
TObjectStorage<T: IStorageObject> = class(TObject)
end;
IKeyStorageObject<TKey> = interface(IStorageObject)
end;
TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>)
end;
TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>)
end;
begin
TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.
This is quite a nuance, the changing of a comma to a semi-colon. Programming by significant punctuation is never much fun. That said, you are familiar with the difference between commas and semi-colons in formal parameter lists and so it should not come as too much of a surprise to see the same distinction drawn here.
The documentation does cover this mind you:
Multiple Type Parameters
When you specify constraints, you separate multiple type parameters by semicolons, as you do with a parameter list declaration:
type TFoo<T: ISerializable; V: IComparable>
Like parameter declarations, multiple type parameters can be grouped together in a comma list to bind to the same constraints:
type TFoo<S, U: ISerializable> ...
In the example above,
S
andU
are both bound to theISerializable
constraint.
这篇关于Delphi - 接口继承与泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!