Expert Delphi
上QQ阅读APP看书,第一时间看更新

Custom attributes

Custom attributes let you add custom information to a class itself or to its individual members. Many libraries that come with Delphi use custom attributes. They are useful when we want to mark certain types or type members that need to be treated in a special way. For example, in the DUnitX unit testing framework that comes with Delphi, we use the Test custom attributes to mark a method as testable and optionally provide parameters to be used by the unit test runner. Another example is the REST API resources, which are published from EMS modules. With custom attributes, we can tell the framework what should be the name of the REST resource to access a certain method.

A custom attribute is just a regular class that inherits from the TCustomAttribute type defined in a built-in system unit.

Let's consider the definition of a custom documentation attribute. A programmer could use such an attribute to associate a given class member in code with a custom URL, with more information about it. Take a look at the following code snippet:

unit uDocAttribute; 
 
interface 
 
type 
  DocAttribute = class(TCustomAttribute) 
  private 
    FURL: string; 
  public 
    constructor Create(URL: string); 
    property URL: string read FURL write FURL; 
  end; 
 
implementation 
 
{ DocAttribute } 
 
constructor DocAttribute.Create(URL: string); 
begin 
  FURL := URL; 
end; 

To apply an attribute, it needs to be placed just before the element it applies in square brackets. Optionally, it can take parameters that just come as a list in brackets. This will implicitly call the custom attribute constructor:

uses uDocAttribute; 
 
type 
  [Doc('http://mydocs/MySuperClass')] // skipping "...Attribute" 
  TMySuperClass = class 
  public 
    [DocAttribute('http://mydocs/MySuperClass/DoSomething')] 
    procedure DoSomething; 
  end; 

By convention, custom attribute class names end with Attribute. Delphi compiler allows us to skip the optional Attribute part of the attribute class name.

That's nice, but how do I know in my code that there are attributes applied to classes that my code operates on? This and many other capabilities are provided by the Runtime Type Information (RTTI) system.