Требуют ли атрибуты Delphi постоянного параметра? Если да, то почему?

#delphi #function #constants

#delphi #функция #константы

Вопрос:

Рассмотрим следующий (не компилируемый) код:

 program AttributesTestProgram;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Classes,
  RTTI;

type

  TDisplayTextAttribute = class(TCustomAttribute)
  private
    FDisplayText: string;
  public
    constructor Create(aDisplayText: string);
    property DisplayText: string read FDisplayText write FDisplayText;
  end;

constructor TDisplayTextAttribute.Create(aDisplayText: string);
begin
  FDisplayText := aDisplayText;
end;

function GetFirstName: string;
begin
  Result := 'First Name';
end;


type
  TCustomer = Class(TObject)
  private
    FFirstName: string;
    FLastName: string;
    FStreetAddress: string;
    FZIP: string;
    FState: string;
    FCity: string;
    FPhone: string;
  published
    [TDisplayTextAttribute(GetFirstName)]
    property FirstName: string read FFirstName write FFirstName;
  end;

begin
  // Code that does the work removed for clarity....
  Readln;
end.
  

Естественно, мне интересно, почему это не удается скомпилировать с ошибкой:

 [DCC Error] AttributesTestProgram.dpr(40): E2026 Constant expression expected
  

Я предполагаю, что это как-то связано с идеей, что атрибуты должны быть привязаны во время компиляции, или что-то в этом роде.

Следовательно, мои вопросы таковы:

Есть ли какой-либо способ «обойти систему» здесь и получить значение времени выполнения в этом месте атрибута?

Ответ №1:

Да, вам нужны константы, потому что параметры вычисляются до констант во время компиляции и хранятся в таблицах RTTI. Кроме того, атрибуты принадлежат классу, а не экземплярам объекта, поэтому, если у вас более одного TCustomer, ваша идея становится бессмысленной.

Вы можете обойти систему, предоставив атрибуту конструктор без параметров (или вообще без конструктора) и изменив свойство DisplayText на его метод, который принимает либо строку, либо объект, из которого вы можете извлечь строку.

Комментарии:

1. Спасибо, Мейсон. Я поиграю с этим.

2. И как мне вызвать этот новый метод при объявлении атрибута?

3. @Nick: … таким же образом, как вы бы вызывали метод для любого другого объекта? (Не уверен, что понимаю ваш вопрос.)

4. Далее, правильный ответ: «Вы не можете превзойти систему, и вам не следует этого хотеть» — что в значительной степени соответствует словам Мейсона. Я нашел другой, правильный способ инициализации параметров конструктора с помощью внедрения зависимостей, передав анонимный метод методу DelegateTo в Delphi Spring — не нужно пытаться настроить атрибут [Injection()].