我在表单的 rtl Streaming 中发生运行时错误,导致在执行 TReader.ReadRootComponent 时引发异常 EClassNotFound。特定的错误消息是“找不到类 TActionList”。
奇怪的是:
- 我的主表单使用操作列表。
- 为了好玩,我将 ActnList.pas(来自 VCL 源文件夹)添加到我的项目中,以尝试修复它。
当我实例化一个直到几分钟前我还在工作的表单时,就会发生这种情况。我所做的更改是在一些子框架代码中:我用 ifdef 标记删除了它的所有实现部分代码,因为我正在模拟一些框架,用于单元测试和原型。
我尝试将操作列表类添加到项目中,并且尝试了使用和不使用各种编译器和链接选项,但是,我仍然得到这个异常。显然有什么奇怪的事情发生了。必须有另一种奇怪的方法来解决这个问题。
事实上,似乎发生了一些非常奇怪的事情。引发此错误时,我得到以下调用堆栈:
rtl.Classes.ClassNotFound('TActionList')
rtl.Classes.TReader.FindComponentClass(???)
rtl.Classes.FindExistingComponent
rtl.Classes.TReader.ReadComponent(nil) /// NIL!? WHAT!!!!!
rtl.Classes.TReader.ReadDataInner(???)
rtl.Classes.TReader.ReadData(???)
rtl.Classes.TComponent.ReadState(???)
vcl.Controls.TControl.ReadState(???)
vcl.Controls.TWinControl.ReadState($60B9CF0)
vcl.Forms.TCustomForm.ReadState(???)
rtl.Classes.TReader.ReadRootComponent($606EB90)
rtl.Classes.TStream.ReadComponent($606EB90)
rtl.Classes.InternalReadComponentRes(???,???,$606EB90)
rtl.Classes.InitComponent(TComplexFormContainingFrames)
似乎 nil 是故意的,在 TReader.ReadDataInner(Instance:TComponent) 中:
while not EndOfList do ReadComponent(nil);
更新:我相信这个问题的答案是理解梅森提到的“序列化上下文”。而且,是时候承认我自己的愚蠢了:我从项目中删除了框架的父级,没有意识到它是框架的父级。我通过存根TMyFrameParent
as的类型声明来解决它丢失的TMyFrameParent = class(TFrame)
问题,这反过来又导致了有问题的条件。我将问题留在这里是因为我认为将来在神秘的情况下何时发生此异常以及如何解决它可能会非常方便。特别是,Mason 有一些关于“序列化上下文”以及它们如何应用于类名查找的非常有趣的信息。