Что на самом деле означает EClassNotFound, созданный во время выполнения, когда рассматриваемый класс присутствует во время компиляции и компоновки, и явно в коде? - PullRequest
7 голосов
/ 02 сентября 2011

У меня ошибка времени выполнения, возникающая в потоковой передаче rtl формы, приводящая к возникновению исключения EClassNotFound при выполнении TReader.ReadRootComponent. Конкретное сообщение об ошибке: «Класс не найден 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);

Обновление: Я полагаю, что ответом на этот вопрос является понимание "контекстов сериализации", как упоминал Мейсон. И пришло время признать мою собственную глупость: я удалил родителя фрейма из проекта, не осознавая, что он был родителем фрейма. Я обошел его, пропустив объявление типа для TMyFrameParent как TMyFrameParent = class(TFrame), и это, в свою очередь, привело к рассматриваемому условию. Я оставляю здесь вопрос, потому что думаю, что в будущем было бы очень удобно заметить, когда это исключение возникает в загадочных случаях и как его исправить. В частности, у Мейсона есть действительно интересная информация о «контекстах сериализации» и о том, как они применяются к определению имен классов.

Ответы [ 5 ]

8 голосов
/ 02 сентября 2011

Это означает, что класс не был найден в текущем контексте десериализации. Не все существующие классы зарегистрированы для всей загрузки. Каждый класс формы имеет RTTI, содержащий ссылки на компоненты, которые он использует. Чтобы это работало, убедитесь, что ваша форма (или фрейм, если это фрейм) объявляет хотя бы один TActionList перед тегом private :

TMyForm = class(TForm)
  ActionList: TActionList;
  OtherComponent: TSomeComponent;
private
  //whatever
public
  //whatever
end;
2 голосов
/ 02 сентября 2011

Используйте Classes.RegisterClass , чтобы зарегистрировать классы, которые вы хотите использовать в потоковой системе.Цитата из документа

Классы форм и классы компонентов, на которые есть ссылки в объявлении формы (переменные экземпляра), автоматически регистрируются.Любые другие классы, используемые приложением, должны быть явно зарегистрированы путем вызова RegisterClass, если необходимо сохранить экземпляры.Как только классы зарегистрированы, они могут быть загружены или сохранены системой потоковой передачи компонентов.

1 голос
/ 02 сентября 2011

Кажется, что это происходит, когда вы копируете фрейм из одного проекта в другой, и этот фрейм наследует от чего-то, и вы фальсифицируете наследование, но оставляете описания "унаследованных" элементов в фрейме dfm, такие элементы:

inherited ActionList: TActionList
  Left = 520
  Top = 576
end

Это, в свою очередь, приводит к «текущему контексту десериализации», о котором говорил Мейсон, не содержащему класс.Одним из исправлений является изменение объекта Inherited во всех вышеперечисленных случаях.

0 голосов
/ 10 мая 2019

Есть еще один способ получить эту ошибку: поместить public в верхнюю часть класса определения формы.По умолчанию члены класса «опубликованы».Я случайно добавил public в верхнюю часть объявления формы, и во время выполнения выдается несколько исключений Class not found.

0 голосов
/ 11 ноября 2018

Я получил ошибку «EClassNotFound», когда в моем файле DFM присутствовало объявление TLabel, но в соответствующем файле PAS для него не было объявления.Каким-то образом редактор форм облажался.

Ошибка не была видна до тех пор, пока я не удалил все метки из моей формы, кроме той, которая была "повреждена".Это было трудно выследить, потому что этот ярлык был спрятан под панелью.

Одно простое решение - вырезать (ctrl + x) этот ярлык (как только вы его найдете) из формы и вставить обратно.На этот раз редактор форм правильно вставит объявление для него в файл PAS.

...