How to obtain the value of a property and how to obtain the property in which the attribute is declared?

Asked

Viewed 1,124 times

1

Let’s say I’m creating an attribute like this:

TCompareAttribute = class(TCustomAttribute)
private
  FPropertyToCompare: string;
public
  constructor Create(APropertyToCompare: string);
  function IsValid: boolean;
end;

implementation

...
function TCompareAttribute.IsValid: boolean;
var
  ctx: TRttiContext;
begin
  ctx := TRttiContext.Create;
  try
    prop := ctx.GetType(self.ClassParent).GetProperty(FPropertyToComparer);
    if prop = nil then
      raise Exception.Create('A propriedade não existe!');

    result := prop.GetValue() = ??

  finally
    ctx.Free;
  end;
end;

The purpose of this attribute is to compare two properties and check if they have the same value, if they are equal.

I have two questions:

1st. How to obtain the property value in the variable "prop" without the instance of the object and;

2nd. How to obtain the property where the attribute is declared and then compare the values?

1 answer

1

If I understand your question correctly, it will depend a little on the way your project was modeled, because there are N ways to dynamically obtain information from the properties of an object.

Answering your questions:

1ª. How to obtain the value of the property in the variable "prop" without the object instance and;

A possible way would be by class name and property via string, e.g.:

var
  ctx: TRttiContext;
  prop: TRttiProperty;
begin
  ctx := TRttiContext.Create;
  try
    prop := ctx.FindType('Unit1.TForm1').GetProperty('Test1');
    ShowMessage(prop.Name);
  finally
    ctx.Free;
  end;
end;

Note that I only gave the name of the form and the property, that is, I did not pass any instance.

2nd. How to obtain the property where the attribute is declared for then compare the values?

In fact it would be "How to check if an attribute is declared on a property?" i.e.:

var
  ctx: TRttiContext;
  prop: TRttiProperty;
  attr: TCustomAttribute;
begin
  ctx := TRttiContext.Create;
  try
    for prop in ctx.FindType('Unit1.TForm1').GetProperties do
      for attr in prop.GetAttributes do
        if attr is TMyAttribute then
          ShowMessage(prop.Name);
  finally
    ctx.Free;
  end;
end;

With this, you can exit the loop if the informed property declares the attribute you are looking for.

Here is an example of how to scan the properties of a form, showing its name, declared attribute and assigned value:

type
  TMyAttribute = class(TCustomAttribute)
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FTest1: string;
    FTest2: string;
  published
    [TMyAttribute]
    property Test1: string read FTest1;
    [TMyAttribute]
    property Test2: string read FTest2;
  end;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  FTest1 := 'A';
  FTest2 := 'B';
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ctx: TRttiContext;
  prop: TRttiProperty;
  attr: TCustomAttribute;
begin
  ctx := TRttiContext.Create;
  try
    for prop in ctx.FindType('Unit1.TForm1').GetProperties do
      for attr in prop.GetAttributes do
        if attr is TMyAttribute then
          ShowMessageFmt(
            'Propriedade "%s" que declara o atributo "%s" tem o valor "%s"',
            [prop.Name, attr.ClassName, prop.GetValue(Self).AsString]);
  finally
    ctx.Free;
  end;
end;

I hope this helps! =)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.