Delphi RTTI,已发布的属性出现两次

标签 delphi

我想对属性使用属性,但这些属性有时会在继承的类中发生更改。这是一个示例代码(非常简化):

  TBaseClass = class(TObject)
  private
    FFoo: string;
  published
    [BaseAttirib('hello')]
    property Foo: string read FFoo;
  end;

  TChildClass = class(TBaseClass)
  published
    [BaseAttirib('good bye')]
    property Foo;
  end;

当我使用 RTTI 浏览属性时,Foo 属性在 GetProperties 数组中出现两次:

var
  xObj: TObject;
  xType: TRttiType;
  xProp: TRttiProperty;
begin
  // FContext is a TRttiContext, already created, not included in this sample
  xObj := TChildClass.Create;
  try
    xType := FContext.GetType(xObj.ClassType);

    for xProp in xType.GetProperties do
    begin
      if not (xProp.Visibility in [mvPublished]) then
        Continue;

      Memo1.lines.add(xProp.Name + ' = ' + xProp.GetValue(xObj).AsString);
    end;
  finally
    FreeAndNil(xObj);
  end;
end;

这是输出:

  Foo = TChildClass
  Foo = TChildClass

将基类中的属性可见性更改为公共(public)可以解决问题,但在我的情况下这是 Not Acceptable ,因为我必须一一增加此属性的可见性以在所有子类中发布。

我的问题是如何防止 Foo 属性重复出现,或者至少有什么方法可以在这些重复之间决定哪一个来自基类,哪一个来自子类?

更新,更多解释:

我们有一个算法,它将对象的所有已发布属性保存到导出文件中,并且 BaseAttrib 属性保存一些必要的信息。 假设我有一个 TBaseClass 实例和一个 TChildClass 实例,对于 TBaseClass,我希望在输出文件中看到“hello”,对于 TChildClass,我希望在输出文件中看到“good bye”。

还值得一提的是,如果我不创建 TBaseClass 的实例并降低 Foo 对公众的可见性,然后引入一个新的可实例化类,在其中发布 Foo 属性,我将丢失 Foo 属性的属性(在TBaseClass)。因此,如果我有 100 个后代类,但我只想更改一个类中的属性值,我仍然需要将相同的属性(带有原始参数)复制到其余 99 个类中。

我想指出的是,这是一个非常简化的示例,我必须在现有的复杂类结构中引入属性,并且我想以最少的方式来做到这一点,而不需要更改/重新编写所有类继承.

如果我可以避免/管理属性重复,那将是最好的方法,这就是我寻找这种解决方案的原因。

最佳答案

My quesion [sic] is how can I prevent the Foo property duplicated appearance, or at least is there any way to decide between these duplications which one came from the base class and which one from the child?

决定哪个属性来自哪个类实际上是微不足道的。以下是 TRttiType.GetProperties 文档的摘录:

The list returned by GetProperties is ordered by the class/interface hierarchy. This means that the most recently included properties are located at the top of the list.

因此,第一个来自子类。

举个例子,考虑一下

type
  TestAttribute = class(TCustomAttribute)
    Value: string;
    constructor Create(S: string);
  end;

  TBaseClass = class(TObject)
  protected
    function GetFoo: string; virtual;
  published
    [Test('x')]
    property Foo: string read GetFoo;
  end;

  TChildClass = class(TBaseClass)
  published
    [Test('y')]
    property Foo;
  end;

然后

function GetTestValueOfFoo(AObject: TBaseClass): string;
begin
  var LRttiType := TRttiContext.Create.GetType(AObject.ClassType);
  if Assigned(LRttiType) then
    for var LRttiProp in LRttiType.GetProperties do
      if LRttiProp.Name = 'Foo' then
        for var LAttrib in LRttiProp.GetAttributes do
          if LAttrib is TestAttribute then
            Exit(TestAttribute(LAttrib).Value);
  Result := '';
end;

将返回类层次结构中最接近 Test 属性的值。所以,

var obj := TChildClass.Create;
try
  ShowMessage(GetTestValueOfFoo(obj))
finally
  obj.Free;
end;

显示y,但如果您从子类的Foo属性中删除Test属性,您将得到x,因为那时它已成为最接近的值。如果没有祖先设置了值,GetTestValueOfFoo 返回空字符串。

关于Delphi RTTI,已发布的属性出现两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65980714/

相关文章:

delphi - 为什么TPanel在Delphi XE中无法显示正确的帧/边框?

android - 德尔福XE8。调音台。为什么Android平台上CLASS VAR的发布顺序不同?

delphi - 如何使用泛型方法和<T>数组的参数数组?

delphi - 如何提高分析的准确性

delphi - 清除 stringgrid 时的 EAcessViolation

delphi - 如何在没有调试器的情况下显示运行时发生异常的行号?

delphi - 通过编辑组件在 FileListbox 中搜索

arrays - Delphi 2007 和动态变量数组作为 Var 参数

delphi - 在设置为 nil 的对象引用上调用 Free 不应该在每次调用时都会引发访问冲突吗?

Delphi Devart SecureBridge POST 请求