7

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

作为代码,我使用了 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.

'TKeyObjectStorage' 的编译器错误是:

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

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

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

4

1 回答 1

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.

原始答案

如果您提供一个显示编译器错误的完整程序会更好。您需要尝试实例化一个对象才能看到该错误。

但是,我想我已经重现了你的问题。所以我认为问题在于这段代码:

TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ...

将通用约束应用于TKeyT。现在,显然您只想应用约束,T因此您需要编写:

TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ...

这是一个在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.

这是一个非常细微的差别,将逗号更改为分号。用重要的标点符号编程从来都不是很有趣。也就是说,您熟悉形式参数列表中逗号和分号之间的区别,因此在这里看到相同的区别应该不会太令人惊讶。

文档确实涵盖了这一点:

多个类型参数

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

type
  TFoo<T: ISerializable; V: IComparable>

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

type
  TFoo<S, U: ISerializable> ...

在上面的示例中,SU都绑定到ISerializable 约束。

于 2013-10-30T12:37:14.373 回答