TDictionary 转换在引用包中失败
TDictionary cast fails in referenced package
TDictionary 已分配给 TObject 变量。我可以在同一项目中将 TOBject 转换回 TDictionary。但是,如果在引用的 bpl 项目中完成转换,则转换会失败,具体取决于引用项目的方式。
测试代码:
procedure TestTDefault.Test1;
var
Obj: TObject;
begin
Obj := TDictionary<string, Integer>.Create;
Check(Obj is TDictionary<string, Integer>);
CheckNotNull(Obj as TDictionary<string, Integer>);
// this calls the function in the referenced bpl package.
// Returns True if Obj can be cast back to a TDictionary.
CheckTrue(TestIfDictionary(Obj)); // outcome depends if referenced packge is included in <DCC_UsePackage>
end;
依赖包中的函数:
function TestIfDictionary(aObject: TObject): Boolean;
begin
Result := aObject is TDictionary<string,Integer>;
end;
我有一个只有两个包的简单项目组:
- DUnit 测试运行器(Package1Tests.exe)
- Package1.bpl
两个包具有相同的 compiler/linker 选项集。
非常奇怪的是,只有当 Package1 未被列为运行时包时,测试才有效:
但是,如果 Package1 被列为运行时包,测试将失败!!
我正在使用 XE2。至于目的,这个问题是在处理RTTI的时候浮出水面的。我能够在这个简单的测试项目中隔离问题。问题与 RTTI 无关。
请注意,如果我不使用 TDictionary 而使用 TStringList,那么测试总是有效。所以问题似乎与泛型有某种关系。
如果需要,我可以提供简单的测试项目。
我花了很多时间来追踪这个问题。我很高兴我发现了引发问题的原因。但不幸的是我不明白为什么会这样。
您应该为此泛型使用类型声明 class。
type
Tx = TDictionary<string, Integer>;
.....
Obj := Tx.Create;
Check(Obj is Tx);
RTTI 在您的情况下无关紧要。
您在这里遇到的问题与泛型实例化有关。每个模块都单独实例化泛型类型,因此它们具有不同的类型标识。这是泛型设计及其与运行时包交互的基本限制。
您可以在包中的一个单元中实例化通用类型,例如:
type
TDictionaryStringInteger = class(TDictionary<string, Integer>);
然后用TDictionaryStringInteger
代替TDictionary<string, Integer>
。但是,这会严重削弱您的代码,因为它会阻止您编写使用泛型类型的泛型方法。
摆脱束缚的另一种方法是停止使用运行时包。坦率地说,这对我来说似乎更有吸引力。
TDictionary 已分配给 TObject 变量。我可以在同一项目中将 TOBject 转换回 TDictionary。但是,如果在引用的 bpl 项目中完成转换,则转换会失败,具体取决于引用项目的方式。
测试代码:
procedure TestTDefault.Test1;
var
Obj: TObject;
begin
Obj := TDictionary<string, Integer>.Create;
Check(Obj is TDictionary<string, Integer>);
CheckNotNull(Obj as TDictionary<string, Integer>);
// this calls the function in the referenced bpl package.
// Returns True if Obj can be cast back to a TDictionary.
CheckTrue(TestIfDictionary(Obj)); // outcome depends if referenced packge is included in <DCC_UsePackage>
end;
依赖包中的函数:
function TestIfDictionary(aObject: TObject): Boolean;
begin
Result := aObject is TDictionary<string,Integer>;
end;
我有一个只有两个包的简单项目组:
- DUnit 测试运行器(Package1Tests.exe)
- Package1.bpl
两个包具有相同的 compiler/linker 选项集。
非常奇怪的是,只有当 Package1 未被列为运行时包时,测试才有效:
但是,如果 Package1 被列为运行时包,测试将失败!!
我正在使用 XE2。至于目的,这个问题是在处理RTTI的时候浮出水面的。我能够在这个简单的测试项目中隔离问题。问题与 RTTI 无关。 请注意,如果我不使用 TDictionary 而使用 TStringList,那么测试总是有效。所以问题似乎与泛型有某种关系。 如果需要,我可以提供简单的测试项目。
我花了很多时间来追踪这个问题。我很高兴我发现了引发问题的原因。但不幸的是我不明白为什么会这样。
您应该为此泛型使用类型声明 class。
type
Tx = TDictionary<string, Integer>;
.....
Obj := Tx.Create;
Check(Obj is Tx);
RTTI 在您的情况下无关紧要。
您在这里遇到的问题与泛型实例化有关。每个模块都单独实例化泛型类型,因此它们具有不同的类型标识。这是泛型设计及其与运行时包交互的基本限制。
您可以在包中的一个单元中实例化通用类型,例如:
type
TDictionaryStringInteger = class(TDictionary<string, Integer>);
然后用TDictionaryStringInteger
代替TDictionary<string, Integer>
。但是,这会严重削弱您的代码,因为它会阻止您编写使用泛型类型的泛型方法。
摆脱束缚的另一种方法是停止使用运行时包。坦率地说,这对我来说似乎更有吸引力。