使用RTTI访问严格私有字段

6
考虑这个简单的代码:
{$APPTYPE CONSOLE}

uses
  Rtti,
  SysUtils;

type
  {$M+}
  TFoo = class
  strict private
    class var Field1 : Integer;
    field2 :  Integer;
  private
    field3 :  Integer;
    class var Field4 : Integer;
  end;


Var
    ctx : TRttiContext;
    f   : TRttiField;
begin
  try
    ctx:=TRttiContext.Create;

    for f in ctx.GetType(TFoo).GetFields do
     Writeln(f.Name);


    Writeln('Done');
    readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

当你运行此代码时,只有field3被列出。似乎RTTI不支持strict privateclass var字段,那么问题是是否可能使用Rtti或其他方法访问Delphi类的strict private字段?我读过RTTI.TRttiType.GetFields方法的文档,但没有提到这些限制。是否存在任何提到这样的限制的论文或文章?

你的语法有问题,显然还没有人发现:field2也是一个类变量!请看我的回答。 - Rudy Velthuis
3个回答

6
我现在无法尝试,但是您似乎需要的可能是 GetDeclaredFields 而不是 GetFields。这应该会给出类的所有(实例)字段,但不包括祖先类的字段。如果您也需要这些字段,您将不得不递归地上溯继承链。
正如我所说,我现在无法尝试,因此您需要自己查看它是否能够让您访问严格私有字段。
更新
请注意,在您声明 TFoo 时,即使您可能没有打算,Field1 和 Field2 都是类变量!
只需重新格式化您的声明,您就会明白我的意思:
  TFoo = class
  strict private
    class var
      Field1: Integer;
      Field2: Integer;
  private
    // etc...

class var 后面的所有内容都是类变量,直到编译器遇到varstrictprivateprotected等关键字为止。试试这个,你也会看到Field2被写入:

  TFoo = class
  strict private
    class var 
      Field1: Integer;
    var 
      Field2: Integer;
    // etc...

或者尝试以下方法:

  TFoo = class
  strict private
    Field2: Integer;
    class var 
      Field1: Integer;
    // etc...

这意味着GetFields和GetDeclaredFields不会受到严格私有字段的影响,它们只是不返回类变量。在我看来,这是有道理的。类变量不是被调查对象的成员。

在这种情况下,GetDeclaredFields函数返回相同的结果。 - Salvador
糟糕!它应该返回更多。 - Rudy Velthuis
1
看一下我回答中的更新。GetFieldsGetDeclaredFields都可以正常工作,包括对于strict private也是如此,但它们不会返回类变量,因为这些实际上不是对象的字段。 - Rudy Velthuis
请注意,在您声明TFoo时,即使您可能没有打算这样做,Field1和Field2都是类变量! - Whiler
谢谢。最后一个问题,你的意思是..类变量不是正在被调查对象的成员.是什么? - Salvador
@Salvador:类变量是类的变量(它们只作为类的一部分存在一次),而不是对象的字段。因此,它们未被列为字段是有道理的。 - Rudy Velthuis

3

2
根据定义,strict private 只能在类本身的范围内可见。但是,它们应该仍然可以通过 Hallvard's hack #5 访问(除了类字段,我想)。

1
不需要黑客技巧来访问严格私有成员,可以使用类助手 :) - LU RD

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