2013-07-27 4 views
9

Я знаю по TMS Aurelius, что мы можем использовать функцию «новых» атрибутов 2010 для сериализации полей таблицы базы данных в свойствах объекта во время выполнения, например, и я не являюсь экспертом в этой схеме с глубокими объектно-ориентированными объектами, поэтому я просматриваю исходный код TMS и не мог понять, как реализовать его сам, а не для БД, а не для XML.Где примеры реального мира в Delphi?

Итак, я искал все результаты Google по Delphi Attributes, и все, что люди публикуют, являются примерами деклараций, а затем останавливаются, даже показывая свои примеры в действии.

Тогда где реальные примеры того, как мы можем проектировать, объявлять, кодировать и использовать эти сочные классы внутри формы/кода выполнения?

У кого-нибудь есть пример, чтобы поделиться здесь или узнать хорошую статью, которая будет завершена?

Edit1:

Ответ должен иметь TForm с TButton, где, при нажатии выполнить некоторое использование классов атрибутов, созданных, не отвечайте показаны только интерфейсы атрибутов и классов, потому что есть много из тех примеров декларации, о которых я рассказывал ранее

+0

есть некоторые тексты, где автор потрудился создать полный файл, содержащий декларацию и строительство методов и интересного использование атрибутов, но не дает нам примера на его использование. – PSyLoCKe

+0

Мне было бы очень интересно - когда-то натолкнулась на ту же «проблему» и никогда не использовала атрибуты, потому что я не вижу преимущества. –

+4

Я думаю, что основная проблема заключается в том, что так долго программисты Delphi настолько привыкли, что не имеют их, что мы не нашли много мест, где они дают явное преимущество по сравнению с тем, как мы это делали. Для многих сторонних поставщиков компонентов широкое использование атрибутов не позволяет им ориентироваться на пользователей более старых версий Delphi, ограничивая их рынки еще больше. – afrazier

ответ

7

Если вы хотите, чтобы объявить вам собственный атрибут, вы можете сделать это следующим образом:

type 
    TDisplayLabelAttribute = class(TCustomAttribute) 
    private 
    FText: string; 
    public 
    constructor Create(const aText: string); 
    property Text: string read FText write FText; 
    end; 

атрибут является обычным классом, который имеет TCustomAttribute как его предок. Вы реализуете его как обычно:

implementation 

constructor TDisplayLabelAttribute.Create(const aText: string); 
begin 
    FText := aText; 
end; 

Теперь атрибут объявлен и реализован, вы можете просто использовать:

[DisplayLabel('My Class')] 
TMyClass = class 
end; 

Так что теперь вы атрибут объявлены и реализованы, и вы использовали его, чтобы добавить ярлык дисплея для некоторого класса. Заключительная фаза - использовать этот атрибут, так как у вас есть класс , украшенный с ним. Код, который использует атрибут, не находится в атрибуте или декорированном классе, он реализован на уровне сервиса, который будет использовать оформление.

Допустим, у нас есть класс, который возвращает возможный отображаемую метку для класса:

type 
    TArtifactInspector = class 
    public 
    class function DisplayLabelFor(aClass: TClass): string; 
    end; 

Этот метод будет проверять класс и вернуть метку дисплея, учитывая, что существует. В противном случае она возвращает пустую строку:

implementation 

uses 
    Rtti; 

class function TArtifactInspector.DisplayLabelFor(aClass: TClass): string; 
var 
    rttiContext: TRttiContext; 
    rttiType: TRttiType; 
    attribute: TCustomAttribute; 
begin 
    rttiContext := TRttiContext.Create; 
    try 
    rttiType := rttiContext.GetType(aClass); 
    for attribute in rttiType.GetAttributes do 
     if attribute is TDisplayLabelAttribute then 
     Exit(TDisplayLabelAttribute(attribute).Text); 
    Result := ''; 
    finally 
    rttiContext.Free; 
    end; // try to recover and return the DisplayLabel 
end; 
+0

нашел еще один пример здесь http://robstechcorner.blogspot.de/2009/10/ini-persistence-rtti-way.html – Franz

+0

Итак, он заменяет te, нужно установить свойства объекта в методе TObject.Create, является что? Я думаю, что для пользователей Delphi в настоящий момент это не обязательно, но для Java это действительно необходимо, потому что у них нет инструментов, которые у нас есть, как у хорошего визуального дизайнера. – PSyLoCKe

+0

@EASI: представленный мной код является лишь примером. Существует много применений атрибутов даже в Delphi. Например, вы можете украсить класс информацией, которая будет использоваться для выполнения сохранения своих экземпляров. В этом случае Object Inspector не поможет вообще. Атрибуты являются важным улучшением в языке, даже для Delphi. Их обычно пропускают многие программисты, которые полагаются только на визуальную часть Delphi. Однако, когда дело доходит до кода, атрибуты могут иметь большое значение. Я предлагаю вам открыть свое мнение о них! – AlexSC

9

Должен сказать, что неясно, какой пример вам нужен. IMHO в http://docwiki.embarcadero.com/RADStudio/XE4/en/Overview_of_Attributes - это все, что вам нужно, возможно, при условии, что у вас есть базовые знания в области аннотации и/или программирования аспект.

Пример зависит от способа/цели автора конкретных используемых SW атрибутов. Вы упомянули систему ORM: типичное использование здесь - аннотировать член класса, представляющего объект БД, с дополнительной информацией, необходимой для работы БД в бэкэнд такой структуры. Пусть Предположим, у вас есть DB объект, имеющий поле COMPANY CHAR (32) NOT NULL, и вы хотите, чтобы представить его в классе Delphi:

TSomeDBEntity = class(...) 
    FCDS: TClientDataset; 
    ... 
    constructor Create; 
    ... 
    [TCharColumn('COMPANY', 32, false)] 
    property CompanyName: string read GetCompanyName write SetCompanyName; 
end; 

тогда вы будете определять атрибут TCharColumn с конструктором

constructor TCharColumn.Create(const AFieldName:string; ALength:integer; ANullable:boolean); 
begin 
    inherited; 
    FName := AFieldName; 
    FLength := ALength; 
    FNullable := ANullable; 
end; 

И использование такой аннотацией может выглядеть примерно так:

FCDS := TClientDataset.Create(nil); 
RttiContext := TRttiContext.Create; 
try 
    RttiType := RttiContext.GetType(self.ClassType); 
    Props := RttiType.GetProperties; 
    for Prop in Props do 
    begin 
     Attrs := Prop.GetAttributes; 
     case Prop.PropertyType.TypeKind of 
     tkUString: 
      begin 
      for Attr in Attrs do 
       if Attr is TCharColumn then 
       begin 
       ColAttr := TCharColumn(Attr); 
       FCDS.FieldDefs.Add(ColAttr.FName, ftString, ColAttr.FLength, not ColAttr.FNullable); 
       end; 
      end; 
     else 
      //... ; 
     end; 
    end; 
finally 
    RttiContext.Free; 
end; 

Эта часть программы показывает, как определить поля в наборе данных в время выполнения на основе аннотаций в Delphi. Мы немного ограничены из-за отсутствия названных параметров, поэтому работа с списком параметров не является гибкой, как должно быть, например, как и в Java (сравните TMS Aurelius аннотации установить http://www.tmssoftware.com/site/manuals/aurelius_manual.pdf и http://www.techferry.com/articles/hibernate-jpa-annotations.html

+0

Из того, что я видел на сайте ORMS ORM, код в начале не знает, какие поля являются табу, поэтому, когда мы используем метод 'Create', структура будет читать базу данных и позволяет нам вводить' MyString: = MyORM.TableName.TableField; 'и в вашем примере вам нужно объявить' [TCharColumn ('COMPANY', 32, false)] '. Не понял ли я истинного использования Атрибутов? – PSyLoCKe

+0

Традиционный подход к созданию таблицы БД состоит в том, чтобы написать команду SQL CREATE TABLE и работать с такой таблицей с помощью SQL. OTOH, в ORM вы не используете команды SQL (кроме ** where **). Таблица DB - это аннотированный класс (содержит атрибуты), и вы управляете данными через ORM. Я не знаю TMS, но, например, Hibernate при запуске проверяет cfg, как обрабатывать схему БД в СУБД в отношении ваших аннотаций: ** проверка **: производство, исключение для исключения в diff, ** обновление **: пытается обновить схему БД в СУБД (не все может быть обновлено) , ** create **, ** create-drop **: отбрасывает существующий DB, включая. данные и создает новую схему БД – pf1957

8

Не уверен, если вопрос просит реальные примеры использования атрибута или как сериализовать таблицы БД в объекты с использованием атрибутов. В приведенном ниже примере надуманная простой (но, тем не менее, пример), показывающий, как использовать атрибуты для регистрации изменений свойств объекта.

Определить пользовательский атрибут

//By convention attributes are *not* prefixed with a `T` 
//and have the word `Attribute` in their name 
LoggableAttribute = class(TCustomAttribute) 
    private 
    FDescription : String; 
    public 
    constructor Create(Description: String); 
    property Description: String read FDescription; 
    end; 

«привет мир» классов TProduct с помощью атрибута

TProduct = Class(TObject) 
    private 
    FPrice: Double; 
    FDescription: String; 
    .. 
    public 
    [LoggableAttribute('Product Price')] 
    property Price : Double read FPrice write SetPrice; 
    [Loggable('Product Description')] {the `Attribute` part is optional} 
    property Description : String read FDescription write SetDescription; 
    property IsDirty : Boolean read FIsDirty; 
    End; 

Любой класс, который имеет «loggable атрибут» может быть передан в этот метод для перебора через свойства и регистрировать их.

procedure LogChanges(LoggableClass: TObject); 
var 
c : TRttiContext; 
t : TRttiType; 
p : TRttiProperty; 
a : TCustomAttribute; 
Value : TValue; 
begin 
c := TRttiContext.Create;  
try 
    t := c.GetType(LoggableClass.ClassType); 
    for p in t.getProperties do 
    for a in p.GetAttributes do 
     if a is TLoggableProperty then begin 
     Value := p.GetValue(LoggableClass); 
     // log to db.. 
     AddLogEntry(p.Name, TLoggableProperty(a).Description, Value.ToString); 
     end; 
finally 
    c.Free; 
end; 

конец;

Пример использования:

var 
P : TProduct; 
begin  
P := TProduct.Create; 
P.LoadPropertiesFromDB; 
... 
... User edits price ...  
... 
P.Price := 499.99; 
... 
... Save product to DB 
if P.IsDirty then // save and log 
    LogChanges(P); 
+0

Возможно, мне стоит изменить вопрос на «как сериализовать таблицы db в объектах с использованием атрибутов» ... :-) – PSyLoCKe

+0

По условным атрибутам do ** not ** есть перед ними 'T' , Также в аннотации может быть опущена часть атрибута 'Атрибут'. Таким образом, атрибут под названием «LoggableAttribute» можно использовать так: '[Loggable ('test')]'. – Johan

+0

Что такое TLoggableProperty? – Mohamad

Смежные вопросы