带class operator Initialize的TFoo记录作为TDictionary键/值报错如何解决?
你定义了带有class operator Initialize的记录类型TFoo,代码如下:
TFoo = record v: int32; class operator Initialize (out Dest: TFoo); // 省略空实现 end;
当将TFoo作为TDictionary的键或值使用时:
a: TDictionary<TFoo, Int32>; // 或 b: TDictionary<Int32, TFoo>;
出现编译错误:Can not open System.Generics.Collections.pas: no such file or directory,同时伴随内部错误:
[dcc32 Fatal Error] System.Generics.Collections.pas(7324): F2084 Internal Error: C31040
查看System.Generics.Collections.pas第7324行,发现代码通过Default()函数初始化字典条目:
FItems[gap].Key := Default(K); FItems[gap].Value := Default(V);
问题根源是自定义的Initialize类操作符与Delphi内置的Default()函数逻辑冲突,触发了编译器bug。
以下是几种可行的解决办法:
替换
Initialize类操作符为记录构造函数
放弃使用class operator Initialize,改为定义显式的构造函数来初始化记录:TFoo = record v: int32; constructor Create; end; constructor TFoo.Create; begin // 原Initialize操作符的初始化逻辑 v := 0; end;使用时通过
TFoo.Create()创建实例,这样不会干扰Default()函数的默认行为,TDictionary可以正常调用Default(TFoo)获取零初始化的记录。显式为记录提供
Default类操作符
自定义Default类操作符,明确指定默认值,覆盖编译器的自动推导逻辑:TFoo = record v: int32; class operator Initialize (out Dest: TFoo); class operator Default: TFoo; end; class operator TFoo.Default: TFoo; begin Result.v := 0; // 定义默认值,比如零初始化 end;这样
Default(TFoo)会调用你自定义的操作符,避免和Initialize操作符产生冲突。移除
Initialize类操作符,改用字段默认值
如果初始化逻辑只是简单的零赋值或固定默认值,可以直接在字段定义时指定默认值,不需要Initialize操作符:TFoo = record v: int32 := 0; // 直接指定字段默认值 end;这种方式下
Default(TFoo)会自动使用字段的默认值,完全兼容TDictionary的初始化逻辑。升级Delphi版本
这个内部错误(C31040)可能是特定版本的编译器bug,尝试升级到较新的Delphi版本(如10.4+),新版本可能已经修复了Initialize操作符与Default()函数的冲突问题。
内容的提问来源于stack exchange,提问作者chabapok

