Delphi RTTI,已发布的属性出现两次 [英] Delphi RTTI, published property appears twice

查看:71
本文介绍了Delphi RTTI,已发布的属性出现两次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to use attributes for properties, but these attributes can change in the inherited class occasionaly. Here is a sample code (very simplified):

  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数组中出现两次:

When Im going thru the properties, using RTTI, the Foo property appears twice in the GetProperties array:

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

在基类中将属性的可见性更改为公开即可解决该问题,但是在我的情况下这是不可接受的,因为我必须逐一增加在所有子类中发布的该属性的可见性.

Changing property visibility to public in the base class would solve the problem, but that is not acceptable in my case, because I would have to increase this property visibility to published in all the child classes one by one.

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

My quesion 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?

更新,更多说明:

我们有一个算法,它将对象的所有已发布属性保存到导出文件中,而BaseAttrib属性包含一些必要的信息.假设我有一个TBaseClass实例和一个TChildClass实例,对于TBaseClass,我想在输出文件中看到"hello",对于TChildClass,我想在输出文件中看到再见".

We have an algorytm which saves an object's all published properties in to an export file and the BaseAttrib attribute holds some neccessary information. Let's say I have an instance of TBaseClass and an instance of TChildClass and for the TBaseClass I want to see 'hello' in the output file and for the TChildClass I want to see 'good bye' in the output file.

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

Also worth to mention, if I wouldn't make instance of TBaseClass and lower the Foo visibility to public and then introduce a new instancable class where I publish the Foo property, I would lose the attribute for the Foo property (introduced in TBaseClass). So if I have 100 descendant classes but I just want to change the attribute value in only one class I would still have to copy the same attribute (with the original param) to the remaining 99 classes.

我想指出的是,这是一个非常简单的示例,我必须在现有的复杂类结构中引入属性,并且我希望以最少的绘画方式做到这一点,而不更改/重新绘制所有类继承

I would like to point that, this is a very simplified example, I have to introduce the attributes in an existing, complex class structure, and I want to do that with the least paintfull way without changing/rewrinting all the class inheritances.

如果我可以避免/管理那是最好的属性重复,那就是为什么我正在寻找那种解决方案.

If I could avoid/manage the property duplications that would be the best way, thats why Im looking for that kind of solution.

推荐答案

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

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 :

Deciding which property comes from which class is actually trivial. Here's an extract from the documentation for TRttiType.GetProperties:

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.

因此,第一个来自子类.

Hence, the first one is from the child class.

例如,考虑

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 属性的值.所以,

will return the value of the closest Test attribute in the class hierarchy. So,

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

显示 y ,但是如果从子类的 Foo 属性中删除 Test 属性,则将获得 x ,因为那样就变成了最接近的值.如果没有祖先设置该值,则 GetTestValueOfFoo 返回空字符串.

shows y, but if you remove the Test attribute from the child class's Foo property, you will instead get x, because then that has become the closest value. GetTestValueOfFoo returns the empty string if no ancestor has the value set.

这篇关于Delphi RTTI,已发布的属性出现两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆