egnew 5 Posted December 6 I have a procedure that loads the properties of a class into a memo: procedure TForm1.GetProperties (p_Class: TClass); var v_Context: TRttiContext; v_Type: TRttiType; v_Property: TRttiProperty; begin v_Type := v_Context.GetType(p_Class); for v_Property in v_Type.GetProperties do Memo1.Lines.Add(v_Property.ToString); end; Sample Usage GetProperties(TFDPhysPGConnectionDefParams); I would like a procedure to get the properties by class name instead of a class. procedure TForm1.GetPropertiesByClassName (p_ClassName: String); // Changed var v_Class: TClass; // Added v_Context: TRttiContext; v_Type: TRttiType; v_Property: TRttiProperty; begin v_Class := GetClass(p_ClassName); // Access Violation Exception v_Type := v_Context.GetType(v_Class); for v_Property in v_Type.GetProperties do Memo1.Lines.Add(v_Property.ToString); end; Sample Usage: v_FDConnection := TFDConnection.Create(nil); try v_FDConnection.DriverName := 'PG'; GetPropertiesByClassName(v_FDConnection.Params.ClassName); finally v_FDConnection.Free; end; My attempt as shown above results in a runtime exception for Access Violation. How can I get this to work? Share this post Link to post
Dmitry Arefiev 105 Posted December 6 v_Context.FindType('FireDAC.Phys.PGDef.TFDPhysPGConnectionDefParams') Share this post Link to post
Remy Lebeau 1421 Posted December 6 (edited) 58 minutes ago, egnew said: I would like a procedure to get the properties by class name instead of a class. Why not use the ClassType instead of the ClassName? GetProperties(v_FDConnection.Params.ClassType); 58 minutes ago, egnew said: My attempt as shown above results in a runtime exception for Access Violation. GetClass() only returns classes that are registered with RegisterClass(). Not all classes are registered. GetClass() returns nil if it can't find the requested class. You are not handling that possibility. You can't pass nil to TRTTIContext.GetType(). FindClass(), on the other hand, will raise an EClassNotFound exception if the requested class is not found. Edited December 6 by Remy Lebeau 1 Share this post Link to post
egnew 5 Posted December 6 I added a function FIndClassByName and was able to get it to work. function TForm1.FindClassByName (const p_ClassName: string): TClass; var v_Context: TRttiContext; v_Type: TRttiType; v_TypeList: TArray<TRttiType>; begin Result := nil; v_Context := TRttiContext.Create; try v_TypeList := v_Context.GetTypes; for v_Type in v_TypeList do begin if v_Type.Name = p_ClassName then begin Result := v_Type.AsInstance.MetaClassType; BREAK; end; end; finally v_Context.Free; end; end; procedure TForm1.GetPropertiesByClassName (p_ClassName: String); var v_Class: TClass; v_Context: TRttiContext; v_Type: TRttiType; v_Property: TRttiProperty; begin Memo1.Lines.Add('----- Properties -----'); v_Class := FindClassByName(p_ClassName); if v_Class <> nil then begin v_Type := v_Context.GetType(v_Class); for v_Property in v_Type.GetProperties do Memo1.Lines.Add(v_Property.ToString); end; end; The FindClassByName function processes a lot of types to get to the one that is needed. Please let me know if there is a better or more efficient way to do this. Share this post Link to post
egnew 5 Posted December 6 18 minutes ago, Remy Lebeau said: Why not use the ClassType instead of the ClassName? Remy: That is what I needed. It works perfectly. Thanks procedure TForm1.GetPropertiesByClassType (p_Class: TClass); var v_Context: TRttiContext; v_Type: TRttiType; v_Property: TRttiProperty; begin Memo1.Lines.Add('----- Properties -----'); v_Type := v_Context.GetType(p_Class); for v_Property in v_Type.GetProperties do Memo1.Lines.Add(v_Property.ToString); end; Share this post Link to post