5

I want to create a function that returns all the names of a certain class as a string list. Based on the previous solution / question I tried to this code with no success

function  GetClassElementNames (TObject ) : TStringlist ;
var
  LCtx : TRttiContext;
  LMethod : TRttiMethod;
begin
  try
    LCtx:=TRttiContext.Create;
    try
      // list the methods for the any class  class
      for LMethod in  LCtx.GetType(TObject).GetMethods do
        result.add(LMethod.Name);
    finally
      LCtx.Free;
    end;
  except
    on E: Exception do
      result.add (E.ClassName + ': ' +  E.Message);
  end;
end;
Frank
  • 2,738
  • 19
  • 30
Franz
  • 1,883
  • 26
  • 47

1 Answers1

14

Use TClass for that, which TRttiContent.GetType() expects anyway.

You are also not allocating the Result before filling it.

Try this:

function GetClassElementNames(Cls: TClass) : TStringlist ;
var
  LCtx : TRttiContext;
  LMethod : TRttiMethod;
begin
  Result := TStringList.Create;
  try
    LCtx := TRttiContext.Create;
    try
      for LMethod in LCtx.GetType(Cls).GetMethods do
        Result.Add(LMethod.Name);
    finally
      LCtx.Free;
    end;
  except
    on E: Exception do
      Result.Add(E.ClassName + ': ' +  E.Message);
  end;
end;

var
  Methods: TStringList;
begin
  Methods := GetClassElementNames(TSomeClass);
  try
    ...
  finally
    Methods.Free;
  end;
end;

If you want to pass in an object instance instead of a class type, you can wrap GetClassElementNames() like this:

function GetObjectElementNames(Object: TObject): TStringList;
begin
  Result := GetClassElementNames(Object.ClassType);
end;

With that said, it is not a good idea to return a new TStringList object. It is better, and more flexible, if the caller allocates the TStringList and passes it to the function to fill in, eg:

procedure GetClassElementNames(Cls: TClass; AMethods: TStrings);
var
  LCtx : TRttiContext;
  LMethod : TRttiMethod;
begin
  try
    LCtx := TRttiContext.Create;
    try
      for LMethod in LCtx.GetType(Cls).GetMethods do
        AMethods.Add(LMethod.Name);
    finally
      LCtx.Free;
    end;
  except
    on E: Exception do
      AMethods.Add(E.ClassName + ': ' +  E.Message);
  end;
end;

{
procedure GetObjectElementNames(Object: TObject; AMethods: TStrings);
begin
  GetClassElementNames(Object.ClassType, AMethods);
end;
}

var
  Methods: TStringList;
begin
  Methods := TStringList.Create;
  try
    GetClassElementNames(TSomeClass, Methods);
    ...
  finally
    Methods.Free;
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Can I exlude all the default functions like Create Free InitInstance CleanupInstance ClassType ClassName ClassNameIs ClassParent ClassInfo InstanceSize InheritsFrom MethodAddress MethodAddress MethodName QualifiedClassName FieldAddress FieldAddress GetInterface GetInterfaceEntry GetInterfaceTable UnitName UnitScope Equals GetHashCode ToString SafeCallException AfterConstruction BeforeDestruction Dispatch DefaultHandler NewInstance FreeInstance Destroy I only need my used defined procedures – Franz Sep 28 '13 at 06:27
  • 4
    Use `TRttiType.GetDeclaredMethods()` instead of `TRttiType.GetMethods()`. That will return only the methods that are explicitly declared in the specified class and ignore any inherited methods that are not overridden in the class. If you want to ignore constructors and destructors, you can check `TRttiMethod.IsConstructor` and `TRttiMethod.IsDestructor` before calling `TStringList.Add()`. – Remy Lebeau Sep 28 '13 at 06:47