我在表单中的 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);
Update:我相信这个问题的答案是理解梅森提到的“序列化上下文”。而且,是时候承认我自己的愚蠢了:我从项目中删除了框架的父级,没有意识到它是框架的父级。我通过存根类型声明来解决它丢失的问题TMyFrameParent
as TMyFrameParent = class(TFrame)
,这又导致了所讨论的情况。我将问题留在这里,因为我认为将来记录在神秘情况下何时发生此异常以及如何修复它可能会非常方便。特别是,梅森有一些关于“序列化上下文”以及它们如何应用于类名查找的非常有趣的信息。