2013-07-27 18 views
9

TMS Aurelius私は、「新しい」2010属性機能を使用してデータベーステーブルフィールドを実行時にオブジェクトプロパティにシリアル化することができます。この深いオブジェクト指向スキーマの専門家ではないので、 TMSのソースコードであり、XMLではなくDB用ではなく、自分自身で実装する方法を理解できませんでした。Delphiの属性の実例はどこにありますか?

私はDelphi AttributesのすべてのGoogleの結果を探しました。その人の投稿はすべて宣言の例であり、実際にその例を示す前に停止します。

次に、フォーム/実行コード内でどのようにそれらのプロジェクトを宣言し、宣言し、コード化し、USEすることができるかについての実際の例はどこですか?

誰かがここで共有したり、良い記事を知っている例がありますか?

EDIT1:

答えが作成した属性クラスのいくつかの使用を実行し、クリックされたとき、多くのがあるので、単に属性とクラスのインタフェースを示す応答しない、TButtonTFormを持っている必要があります私が前に言ったような宣言の例のうち

+0

:それ以外の場合は、空の文字列を返します。 – PSyLoCKe

+0

私はいつも同じ問題に直面していて、利益を見ていないので属性を使ったことは一度もありませんでした。 –

+4

私は根本的な問題は、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

がもう1つ見つかりましたhttp://robstechcorner.blogspot.de/2009/10/ini-persistence-rtti-way.html – Franz

+0

したがって、TObject.Createメソッドでオブジェクトのプロパティを設定する必要があります。それ? Delphiのユーザーにとっては現時点では必要ではないと考えていますが、実際の優れたビジュアルデザイナーのようなツールがないため、Javaの場合は本当に必要です。 – PSyLoCKe

+0

@EASI:私が提示したコードは単なる例に過ぎません。 Delphiでも属性には多くの用途があります。たとえば、インスタンスの永続性を実行するために使用される情報でクラスを修飾することができます。その場合、オブジェクトインスペクタはまったく役に立たないでしょう。属性はDelphiの場合でも言語の重要な改善点です。それらは通常、Delphiの視覚的な部分にのみ依存する多くのプログラマによって見過ごされています。しかし、コードに関しては、属性が大きな違いを生む可能性があります。私は彼らについてあなたの心を開くことをお勧めします! – AlexSC

9

私には、どのような例が必要かはあまり明確ではありません。 http://docwiki.embarcadero.com/RADStudio/XE4/en/Overview_of_AttributesのIMHOはあなたが必要とするすべてのものです。おそらく、アノテーションやアスペクトのプログラミングに関するいくつかの基本的な知識が必要です。

例は、特定のSWの作成者が属性を使用する方法/目的によって異なります。あなたはORMシステムについて言及しました。ここでの典型的な使用法は、DBエンティティを表すクラスのメンバに、そのようなフレームワークのバックエンドでのDB操作に必要な追加情報を注釈することです。あなたがNULL DBエンティティ有する電界COMPANY CHAR(32)NOTを持っていて、Delphiのクラスでそれを表現したいと仮定しましょう:

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

、あなたはコンストラクタ

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

と使用して属性TCharColumnを定義しますそのような注釈のようなものになります:

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アウレリウス注釈がhttp://www.tmssoftware.com/site/manuals/aurelius_manual.pdfhttp://www.techferry.com/articles/hibernate-jpa-annotations.html

+0

私はTMS ORMサイトで見たものから、最初はコードがどのタブのフィールドなのかわからないので、 'Create'メソッドを使うと、フレームワークはデータベースを読み込み、 MyString:= MyORM.TableName.TableField;そしてあなたの例では '[TCharColumn( 'COMPANY'、32、false)]'を宣言しなければなりません。私はAttributesの本当の使い方を誤解しましたか? – PSyLoCKe

+0

DBテーブルを作成する伝統的なアプローチは、SQLコマンドCREATE TABLEを作成し、SQLを使用してそのようなテーブルで操作することです。 OTOH、ORMでは、SQLコマンドは使用しません(ただし** **句は除く)。 DBテーブルには注釈付きクラス(属性を含む)があり、ORMを介してデータを操作します。私はTMSを知らないが、例えば起動時のHibernateは、注釈に関するRDBMSのDBスキーマを扱う方法をcfgで検証します:** validate **:production、diffの例外をスローします** update **:RDBMSのDBスキーマを更新しようとします(すべて更新することはできません) 、** create **、** create-drop **:既存のDBを削除します。データを作成し、新しいDBスキーマを作成する – pf1957

8

わからないを設定したり、属性を使用してオブジェクトにDBテーブルをシリアライズする方法。以下の例は、不自然な単純なものです(その例はあまりありません)、属性を使用してオブジェクトプロパティの変更を記録する方法を示しています。

属性

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; 

「ログ可能属性」を持つすべてのクラスを使用してTProduct

//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; 

クラスの「Hello World」のカスタム属性を定義する反復するために、このメソッドに渡すことができますプロパティを介してログに記録します。

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; 

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

「データベーステーブルを属性を使用してオブジェクトにシリアル化する方法」を変更する必要があるかもしれません。 – PSyLoCKe

+0

従来の属性では、**の前に 'T 'はありません。アノテーションでは、名前の 'Attribute'部分を省略することもできます。したがって、 'LoggableAttribute'という属性は' [Loggable( 'test')] 'のように使用できます。 – Johan

+0

TLoggablePropertyとは何ですか? – Mohamad

関連する問題