Даже я столкнулся с подобной ошибкой при запуске json.dump (). В моем случае я получал строку ошибки:
AttributeError: у объекта 'file' нет атрибута 'dump'
Как я это исправил -
Я использовал имя переменной как "JSON" для дескриптора файла в том же сценарии, поэтому я получил эту ошибку. Поэтому я просто переименовал имя переменной и проблема разрешилась.
Как упоминал Джим, вы можете использовать константы класса или перечислимый тип:
type
TItemStatus = (isOpen, isActive, isClosed);
const
ItemStatusStrings: array[TItemStatus] of string = ('Open', 'Active', 'Closed');
См. http: //edn.embarcadero.com/article/34324 («Новые возможности языка Delphi начиная с Delphi 7».
Подойдет константа класса. Из приведенной выше ссылки:
type
TClassWithConstant = class
public
const SomeConst = 'This is a class constant';
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowMessage(TClassWithConstant.SomeConst);
end;
Или вы можете объединить @ Jim и @ TOndrej
TGlobalConsts = class
type
TItemStatus = (isOpen, isActive, isClosed);
const
ItemStatusStrings: array[TItemStatus] of string = ('Open', 'Active', 'Closed');
end;
Хотя вы могли бы сделать его классом или записью на самом деле. Хотя, если это класс , вы можете добавить функции класса , например, @ mghie , и вместо этого просто получить значения из массива const ]. Лично я предпочитаю иметь все строки в массиве констант в интерфейсе вместо того, чтобы засыпать их в телах функций в реализации . 1290] Есть много способов сделать это, это точно.
Я лично широко использовал подход TOndrej на нескольких крупных платформах обработки критически важных данных. Преимущество перечислений в том, что их можно легко передавать в приложении, они очень компактны (порядковый тип), отлично работают с операторами case и полностью безопасны по типу. Последний момент важен для обслуживания, так как удаление или изменение значений перечисления вызовет ошибку компиляции (хороший вариант, ИМХО).
Некоторые проблемы, на которые следует обратить внимание при этом подходе:
Изменение объявленного порядка значений перечисления приведет к ошибкам запретить поисковый массив enum-> string.
Если вы используете операторы enum in case (хорошая функция), обязательно учитывайте добавляемые новые значения. Обычно я добавляю else к случаю и создаю исключение для неизвестных значений. Гораздо лучше, чем провалиться.
Если вас очень беспокоит первая проблема, вы можете использовать запись в поисковом массиве и включить значение перечисления в каждую запись и проверить порядок при инициализации модуля. Это много раз спасало мой бекон в критически важных системах, где требуется частое обслуживание. Этот подход также можно использовать для добавления дополнительных метаданных к каждому значению (очень удобная функция).
Удачи!
unit Unit1;
interface
type
TItemStatusEnum = (isOpen, isActive, isClosed);
TItemStatusConst = class
class function EnumToString(EnumValue : TItemStatusEnum): string;
property OPEN: string index isOpen read EnumToString;
property CLOSED: string index isClosed read EnumToString;
property ACTIVE: string index isActive read EnumToString;
end;
var
ItemStatusConst : TItemStatusConst;
implementation
uses
SysUtils;
type
TItemStatusRec = record
Enum : TItemStatusEnum;
Value : string;
end;
const
ITEM_STATUS_LOOKUP : array[TItemStatusEnum] of TItemStatusRec =
((Enum: isOpen; Value: 'OPEN'),
(Enum: isActive; Value: 'ACTIVE'),
(Enum: isClosed; Value: 'CLOSED'));
procedure ValidateStatusLookupOrder;
var
Status : TItemStatusEnum;
begin
for Status := low(Status) to high(Status) do
if (ITEM_STATUS_LOOKUP[Status].Enum <> Status) then
raise Exception.Create('ITEM_STATUS_LOOKUP values out of order!');
end;
class function TItemStatusConst.EnumToString(EnumValue: TItemStatusEnum): string;
begin
Result := ITEM_STATUS_LOOKUP[EnumValue].Value;
end;
initialization
ValidateStatusLookupOrder;
end.
Обновление:
Спасибо за критику - вы абсолютно правы в том, что я решал что я воспринимал как проблему, лежащую в основе вопроса. Ниже приводится гораздо более простой подход, если вы можете жить с ограничением, что он должен работать ТОЛЬКО в Delphi 2007 или более поздних версиях (может работать в D2006?). Трудно избавиться от назойливых мыслей об обратной совместимости;)
type
ItemStatusConst = record
const OPEN = 'OPEN';
const ACTIVE = 'ACTIVE';
const CLOSED = 'CLOSED';
end;
Этот подход прост и похож на то, что можно сделать в приложении Java или .Net. Семантика использования соответствует ожиданиям и будет работать с автозавершением кода. Большим плюсом является то, что константы имеют область видимости на уровне записи, поэтому нет риска конфликтов с другими определениями, как это происходит с типами с единичной областью видимости.
Sample usage:
ShowMessage(ItemStatusConst.ACTIVE);
ShowMessage(ItemStatusConst.CLOSED);
Ради забавы, я также пересмотрел свой предыдущий подход, чтобы напрямую ответить на исходный вопрос. с аналогичным исходом. На этот раз я использовал «смоделированные свойства класса» (см. здесь ) с индексатором свойств. Это явно более сложный, чем рекордный подход, но сохраняет возможность работы со значениями перечисления, наборами, строками И также может быть расширен для реализации дополнительных функций метаданных, где это необходимо. Я считаю, что это работает для версий Delphi, начиная с Delphi 5 IIRC.
Примером того, где я использовал этот метод с большим эффектом, была структура синтаксического анализа, которую я создал в Delphi для обработки полной IBM AFPDS печатает грамматику потока данных. Благодаря этой гибкости я люблю работать в Delphi - это как швейцарский армейский нож;)
Примером того, где я использовал эту технику с большим эффектом, был фреймворк синтаксического анализа, который я создал в Delphi для обработки полной грамматики потока данных печати IBM AFPDS . Благодаря этой гибкости я люблю работать в Delphi - это как швейцарский армейский нож;)
Примером того, где я использовал эту технику с большим эффектом, был фреймворк синтаксического анализа, который я создал в Delphi для обработки полной грамматики потока данных печати IBM AFPDS . Благодаря этой гибкости я люблю работать в Delphi - это как швейцарский армейский нож;)
Это то, что вы можете делать во всех версиях Delphi:
type
TStatus = class
class function Active: string;
class function Open: string;
...
end;
class function TStatus.Active: string;
begin
Result := 'ACTIVE';
end;
class function TStatus.Open: string;
begin
Result := 'OPEN';
end;
Вы можете использовать это именно так, как хотите:
MyVar := TStatus.Open;
есть ровно одно место для изменения строк, и там задействован только код, без создания экземпляра во время выполнения. Новые возможности последних версий Delphi не всегда необходимы для подобных вещей ...
У вас может быть глобальная переменная типа записи. Тип записи должен иметь поле для каждого вашего статуса.
Вы можете заполнить запись в разделе Initialize любого модуля, вызвав процедуру или функцию, объявленную в этом модуле. У вас может быть одно устройство, специально предназначенное для этой работы, например StatusTypes.pas.
В разделе интерфейса вы можете объявить что-то вроде:
type
TStatus = record
OPEN: string;
end;
var
Status: TStatus;
В дополнение к тому, что сказал TOndrej:
Можно также объявить константу записи:
type
TRecordName = record
Field1: Integer;
Field2: String
end;
const
itemstatus : TRecordName = (
Field1: 0;
Field2: 'valueoffield2'
);
Также возможен массив записей путем объединения записи const
синтаксис выше и синтаксис массива, показанный TOndrej.
Однако способ, который я обычно предпочитаю, требует инициализации:
TStringDynArray
именами перечисления через RTTI