Home > other >  How to transform a class name string to a class object?
How to transform a class name string to a class object?

Time:07-18

In a 32-bit VCL Application in Windows 10 in Delphi 11 Alexandria, I am trying to write a small app that finds the list of ANCESTORS from a class name that the user inputs in an Edit box:

procedure TForm1.DoShowAncestors(const aClassName: string);
var
  ClassRef: TClass;
begin
   lstAncestors.Clear;

   // Does not work:
   //ClassRef := TClass.Create;
   //ClassRef.ClassName := aClassName;

   // [dcc32 Error] E2076 This form of method call only allowed for class methods or constructor:
   ClassRef := TClass(aClassName).ClassType;

   while ClassRef <> nil do
   begin
     lstAncestors.Items.Add(ClassRef.ClassName);
     ClassRef := ClassRef.ClassParent;
   end;
end;

procedure TForm1.edtClassNameKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_RETURN then
  begin
    DoShowAncestors(Trim(edtClassName.Text));
  end;
end;

However, the problem is to transform the input string into a TClass object. See the above error comments.

CodePudding user response:

Since Delphi is a compiled language, obtaining a class (or object) by name is not a natural operation, but requires some kind of framework.

Fortunately, modern RTTI (uses RTTI) can easily handle this for you:

procedure ShowAncestors(const AClass: string);
begin

  var Ctx := TRttiContext.Create;
  try
    var LType := Ctx.FindType(AClass);
    if LType is TRttiInstanceType then
    begin
      var R := TRttiInstanceType(LType).MetaclassType;
      while Assigned(R) do
      begin
        ShowMessage(R.ClassName);
        R := R.ClassParent;
      end;
    end;
  finally
    Ctx.Free; // actually, just to make the code "look" right!
  end;

end;

Try it with

ShowAncestors('Vcl.Forms.TForm')

for instance.

(Of course, this only works for classes actually included in the final EXE.)

CodePudding user response:

Now there is no more need to enter a fully qualified class name:

enter image description here

function FindMyClass(const Name: string): TClass;
var
  ctx: TRttiContext;
  ThisType: TRttiType;
  ThisList: TArray<TRttiType>;
begin
  Result := nil;
  ctx := TRttiContext.Create;
  try
    ThisList := ctx.GetTypes;
    for ThisType in ThisList do
    begin
      if ThisType.IsInstance and (EndsText(Name, ThisType.Name)) then
      begin
        Result := ThisType.AsInstance.MetaClassType;
        BREAK;
      end;
    end;
  finally
    ctx.Free;
  end;
end;

procedure TForm1.DoShowAncestors(const aClassName: string);
var
  ClassRef: TClass;
begin
   lstAncestors.Items.BeginUpdate;
   try
     lstAncestors.Clear;

     ClassRef := FindMyClass(aClassName);

     while ClassRef <> nil do
     begin
       lstAncestors.Items.Add(ClassRef.ClassName);
       ClassRef := ClassRef.ClassParent;
     end;

   finally
     lstAncestors.Items.EndUpdate;
   end;
end;
  • Related