Delphi - 接口继承与泛型 [英] Delphi - Interface inheritance with generics

查看:288
本文介绍了Delphi - 接口继承与泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前遇到编译错误,我们公司没有人可以帮助,我很遗憾的是找不到SO或谷歌的正确搜索模式。



作为代码我正在使用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 and U are both bound to the ISerializable constraint.

这篇关于Delphi - 接口继承与泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆