2011-09-02 7 views
5

Tengo un error en el tiempo de ejecución que ocurre en el rtl Flujo de un formulario, lo que hace que se levante una excepción EClassNotFound, mientras hago TReader.ReadRootComponent. El mensaje de error particular es "Class not found TActionList".¿Qué significa realmente un EClassNotFound generado en tiempo de ejecución cuando la clase en cuestión está allí en tiempo de compilación y enlace, y explícitamente en el código?

Lo que es extraño es:

  1. Mi forma principal utiliza la lista Acción.
  2. Por diversión, agregué ActnList.pas (desde la carpeta de origen de VCL) a mi proyecto, para tratar de solucionarlo.

Esto me sucede al crear una instancia de un formulario que tenía trabajando hasta hace unos minutos. El cambio que hice fue en un código de subframe: eliminé todo su código de sección de implementación con un marcador ifdef, porque estoy burlando algunos fotogramas, para pruebas unitarias y prototipos.

Intenté agregar la clase de lista de acciones al proyecto, y probé con y sin varias opciones de compilación y enlace, y aún así, sigo recibiendo esta excepción. Obviamente, algo raro está sucediendo. Debe haber otra forma extraña de tener este problema.

De hecho, parece que pasa algo realmente extraño. Cuando se eleva este error, me sale el siguiente pila de llamadas:

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) 

Parece que la nula es intencional, en TReader.ReadDataInner (Instancia: TComponent):

 while not EndOfList do ReadComponent(nil); 

Actualización: Creo la respuesta a esta pregunta es comprender los "contextos de serialización" como lo ha mencionado Mason. Y, es hora de admitir mi propia estupidez: eliminé el padre del marco del proyecto, sin darme cuenta de que era el padre del marco. Me di cuenta de que faltaba anulando la declaración de tipo para TMyFrameParent como TMyFrameParent = class(TFrame), y esto a su vez conduce a la condición en cuestión. Dejaré la pregunta aquí porque creo que en el futuro podría ser muy útil notar cuándo se produce esta excepción en casos arcanos y cómo solucionarla. En particular, Mason tiene información muy interesante sobre los "contextos de serialización" y cómo se aplican a la búsqueda de nombres de clase.

+1

El nil solo le indica a ReadComponent que crea una nueva instancia en lugar de leer en una existente. –

Respuesta

6

Significa que la clase no se encontró en el contexto de deserialización actual. No todas las clases existentes están registradas para todas las cargas. Cada clase de formulario tiene RTTI que contiene referencias a los componentes que utiliza. Para conseguir que esto funcione, asegúrese de que su forma (o el marco, si se trata de un marco) declara al menos un TActionList antes de la etiqueta privada:

TMyForm = class(TForm) 
    ActionList: TActionList; 
    OtherComponent: TSomeComponent; 
private 
    //whatever 
public 
    //whatever 
end; 
2

Uso Classes.RegisterClass para registrar las clases que desee utilizar con el sistema de transmisión Cita del documento

Las clases de formulario y las clases de componentes a las que se hace referencia en una declaración de formulario (variables de instancia) se registran automáticamente. Cualquier otra clase utilizada por una aplicación debe registrarse explícitamente llamando a RegisterClass si se van a guardar instancias. Una vez que se registran las clases, el sistema de transmisión de componentes las puede cargar o guardar.

+0

Por lo tanto, en el caso de un marco que hereda de otro marco, probablemente esto explique por qué Classes.RegisterClass nunca se invocó, porque el .dfm del marco contiene solo una entrada "heredada x", no la entrada "objeto x". –

+0

Hay algo sospechoso ... si el proyecto no contenía el marco principal, ¿cómo es que el sistema de transmisión buscó la clase TActionList? Debido a que el dfm para el marco descendiente estaba vacío (es decir, no contiene ActionList), ¿verdad? – ain

1

Parece que esto sucede cuando se copia un marco de un proyecto a otro proyecto, y que el marco hereda de algo, y falsa la herencia, pero deje las descripciones de los artículos "heredadas" en el DFM marco, elementos de esta manera:

inherited ActionList: TActionList 
    Left = 520 
    Top = 576 
end 

esto a su vez resulta en el "contexto actual deserialización" que hablaba de Mason, que no contiene la clase. Una solución es cambiar Inherited to object en todos los casos anteriores.

Cuestiones relacionadas