8

我在表单的 rtl Streaming 中发生运行时错误,导致在执行 TReader.ReadRootComponent 时引发异常 EClassNotFound。特定的错误消息是“找不到类 TActionList”。

奇怪的是:

  1. 我的主表单使用操作列表。
  2. 为了好玩,我将 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);

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

4

5 回答 5

9

这意味着在当前反序列化上下文中找不到该类。并非所有现有类都为所有加载注册。每个表单类都有 RTTI,其中包含对其使用的组件的引用。要使其工作,请确保您的表单(或框架,如果这是一个框架)在私有标记之前声明至少一个 TActionList:

TMyForm = class(TForm)
  ActionList: TActionList;
  OtherComponent: TSomeComponent;
private
  //whatever
public
  //whatever
end;
于 2011-09-02T18:40:09.650 回答
2

使用Classes.RegisterClass来注册要与流系统一起使用的类。从文档中引用

表单声明中引用的表单类和组件类(实例变量)会自动注册。如果要保存实例,则必须通过调用 RegisterClass 显式注册应用程序使用的任何其他类。一旦类被注册,它们就可以被组件流系统加载或保存。

于 2011-09-02T19:29:28.380 回答
1

当您将一个框架从一个项目复制到另一个项目时,似乎会发生这种情况,并且该框架继承自某些东西,并且您伪造了继承,但将“继承的”项目描述留在框架 dfm 中,项目如下:

inherited ActionList: TActionList
  Left = 520
  Top = 576
end

这反过来导致 Mason 谈到的“当前反序列化上下文”,不包含该类。一种解决方法是在上述所有情况下将 Inherited 更改为 object。

于 2011-09-02T19:52:28.737 回答
0

当我的 DFM 文件中存在 TLabel 声明但相应的 PAS 文件中没有它的声明时,出现“EClassNotFound”错误。不知何故,表单编辑器搞砸了。

直到我从表单中删除除特定“损坏”标签之外的所有标签之前,该错误才可见。很难找到它,因为该标签隐藏在面板下。

一个简单的解决方法是从表单中剪切(ctrl+x)该标签(一旦找到它)并将其粘贴回来。这次表单编辑器将在 PAS 文件中正确插入声明。

于 2018-11-11T20:44:15.610 回答
0

还有另一种方法可以得到这个错误:将“public”放在表单定义类的顶部。默认情况下,类成员是“已发布”。我不小心在表单声明的顶部添加了“公共”,它在运行时产生了多个“找不到类”异常。

于 2019-05-10T14:29:50.673 回答