Declaring Custom Attributes (RTTI)
Go Up to Attributes (RTTI)
This topic describes the basic methods used to create custom attributes, the proper design decisions for attribute classes, and the general use cases.
Contents
Declaring an Attribute
An attribute is a simple class type. To declare your own custom attribute, you must derive it from a special predefined class: System.TCustomAttribute:
type
MyCustomAttribute = class(TCustomAttribute)
end;
MyCustomAttribute
can then be used to annotate any type or any member of a type (such as class, record, or interface):
type
[MyCustomAttribute]
TSpecialInteger = type integer;
TSomeClass = class
[MyCustomAttribute]
procedure Work;
end;
Note that the declared attribute class must not be declared as class abstract and should not contain any abstract methods. Even though the compiler allows you to use these attributes for annotation, the built binary will not include them in the emitted RTTI information.
Attribute Names that End with 'Attribute' are Implicitly Shortened
Suppose you define two TCustomAttribute
subclasses with the same name prefix, but one has 'Attribute' as a suffix, such as:
MyCustom
MyCustomAttribute
The class with the 'Attribute' suffix (MyCustomAttribute
) is always used, and the class with the shorter name (MyCustom
) becomes inaccessible.
The following code snippet demonstrates this issue. One might expect the TCustomAttribute
subclass, Test
, to be applied but because of implicit name shortening, TestAttribute
will actually be applied where either [Test]
or [TestAttribute]
are used.
type
// To check ambigious names
TestAttribute = class(TCustomAttribute)
end;
// Becomes unaccessible
Test = class(TCustomAttribute)
end;
[Test] // Resolves to TestAttribute at run time
TAmbigiousClass = class
end;
Constructors in Attributes
Normally, an attribute is designed to carry some additional information that can be queried at run time. To allow specifying custom information for the attribute class, you must declare constructors for it:
type
AttributeWithConstructor = class(TCustomAttribute)
public
constructor Create(const ASomeText: String);
end;
which can then be used as follows:
type
[AttributeWithConstructor('Added text value!')]
TRecord = record
FField: Integer;
end;
The method resolution works for attributes as well, which means that you can define overloaded constructors in the custom-defined attribute. Declare only constructors that accept constant values and not out
or var
ones. This comes out of a basic restriction in how attributes work and is discussed in more detail in Annotating Types and Type Members.