How to create and attach custom attribute to field at runtime in Delphi
Asked Answered
C

2

6

Is it possible and how to create and attach custom attribute to field at runtime?

uses
  System.SysUtils,
  System.Classes,
  System.Rtti;

type
  MyAttribute = class(TCustomAttribute)
  private
    fCaption: string;
  public
    constructor Create(const aCaption: string);
    property Caption: string read fCaption write fCaption;
  end;

  TFoo = class(TPersistent)
  public
    [MyAttribute('Title')]
    Bar: string;
    Other: string;
  end;

constructor MyAttribute.Create(const aCaption: string);
begin
  fCaption := aCaption;
end;

procedure CreateAttributes(Typ: TRttiType);
var
  Field: TRttiField;
  MyAttr: MyAttribute;
begin
  for Field in Typ.GetFields do
    begin
      if Length(Field.GetAttributes) = 0 then
        begin
          MyAttr := MyAttribute.Create('Empty');
          // how to attach created attribute to Field ???
        end;
    end;
end;

var
  Context: TRttiContext;
  Typ: TRttiType;
  Field: TRttiField;
  Attr: TCustomAttribute;

begin
  Context := TRttiContext.Create;
  Typ := Context.GetType(TFoo);

  CreateAttributes(Typ);

  for Field in Typ.GetFields do
    for Attr in Field.GetAttributes do
      if Attr is MyAttribute then 
        writeln(Field.Name + ' ' + MyAttribute(Attr).Caption);
  readln;
  Context.Free;
end.

Running above code produces output:

Bar Title

I would like to inject MyAttribute with value Empty to fields that don't have it at runtime producing following output:

Bar Title
Other Empty
Continual answered 28/3, 2015 at 12:59 Comment(0)
H
2

The framework provides no mechanism for attaching attributes at runtime. Any attempt to do so would involve hacking the framework.

Haroldson answered 28/3, 2015 at 13:3 Comment(4)
I though this might be so. That only proves that attributes are not much better suited for serialization than published directive.Continual
@Dalija why would serialization options vary at runtimeHaroldson
One reason for this is altering serialization of classes beyond your control, like in JSON serialization without garbageContinual
Another reason for changing serialization options is that with attributes you are creating extremely tight coupling between class and serialization framework. Changing from one JSON library to another could be nightmare, and imagine if you have to use several frameworks at once and have to serialize to JSON and XML for instance. RTTI (without attributes) (including published directive) gives you much more flexibility and looser coupling. In well designed serialization framework, you can create field mappings, add converters, filters and other customization without forcing changes upon classesContinual
N
0

Attributes is compile-time magic. In run-time you don't need such things. Just create own dictionary where of type and member (member can be set as string) is key, and list of attributes is value. And, when you need to check attributes do it by two ways - common and in your dictionary.

Narcosynthesis answered 28/3, 2015 at 14:57 Comment(1)
Thanks, but that does not solve the issue when you have class beyond your control (you cannot change it in compile time) and you have to perform attribute based operation (again beyond your control) upon it. Look at JSON serialization without garbage for more insight what I am talking about.Continual

© 2022 - 2024 — McMap. All rights reserved.