我可以将一个类类型作为过程参数传递吗?

5

我希望创建一个函数,返回指定类别的所有名称组成的字符串列表。根据之前的解决方案/问题,我尝试了以下代码,但没有成功。

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;
1个回答

14

使用TClass可以达到这个效果,而TRttiContent.GetType()也需要它。

你在填充之前也没有为结果进行分配。

尝试这个:

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;

如果您想传递一个对象实例而不是类类型,您可以像这样包装GetClassElementNames()

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

话虽如此,但是返回一个新的TStringList对象不是一个好主意。更好、更灵活的做法是让调用者分配TStringList并将其传递给函数填充,例如:

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;

我能排除所有默认函数,如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。我只需要我定义的程序。 - Franz
4
请使用TRttiType.GetDeclaredMethods()代替TRttiType.GetMethods()。这将仅返回在指定类中显式声明的方法,并忽略任何未在该类中被覆盖的继承方法。如果想要忽略构造函数和析构函数,可以在调用TStringList.Add()之前检查TRttiMethod.IsConstructorTRttiMethod.IsDestructor - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接