Delphi - 使用泛型的接口继承

Hug*_*gie 7 delphi generics inheritance delphi-xe2

我目前陷入编译错误,我们公司没有人可以提供帮助,我很遗憾没有找到SO或谷歌的正确搜索模式.

作为代码,我使用2个接口,继承和2个类,继承.以下代码重现错误:

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.
Run Code Online (Sandbox Code Playgroud)

'TKeyObjectStorage'的编译错误是:

[DCC错误] Project22.dpr(11):E2514类型参数'T'必须支持接口'IStorageObject'

我认为,编译器没有正确识别类'TKeyObjectStorage'的参数T. 它应该是正确的,因为想要的Type'IKeyStorageObject'具有父类型IStorageObject.

为什么这不起作用?我究竟做错了什么?这在德尔福是不可能的吗?

Dav*_*nan 9

更新

最初的问题出现了我发现的问题(见下文).但是,我描述的修复程序适用于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;
end.
Run Code Online (Sandbox Code Playgroud)

原始答案

如果您提供了一个显示编译器错误的完整程序,那会更好.您需要尝试实例化一个对象以查看该错误.

但是,我想我已经复制了你的问题.所以我认为问题在于这段代码:

TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ...
Run Code Online (Sandbox Code Playgroud)

将通用约束应用于TKeyT.现在,显然你只想要应用约束,T所以你需要写:

TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ...
Run Code Online (Sandbox Code Playgroud)

这是一个简短的程序,可以根据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.
Run Code Online (Sandbox Code Playgroud)

这是一个很细微的差别,将逗号更改为分号.通过重要标点编程从来没有太多乐趣.也就是说,你熟悉正式参数列表中逗号和分号之间的区别,所以看到这里画出的相同区别不应该太令人惊讶.

文件确实涉及这个你要知道:

多种类型参数

指定约束时,可以使用分号分隔多个类型参数,就像使用参数列表声明一样:

type
  TFoo<T: ISerializable; V: IComparable>
Run Code Online (Sandbox Code Playgroud)

与参数声明一样,可以在逗号列表中将多个类型参数组合在一起以绑定到相同的约束:

type
  TFoo<S, U: ISerializable> ...
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,S并且U都绑定到ISerializable 约束.