2017-02-21 2 views
1

rttiを使用して事前設定された値を使用してクラスを作成する必要があります。値は属性から取得されます。フィールドに値を追加する必要があるときは、すべてが正常に動作します。適切なプロパティを見つけ、その属性の値が真であることを取得します。しかし、記録は操作されていません。どこが間違っているか教えてくださいフィールドにRTTIで値を記録する

program DemoGenerator; 
{$APPTYPE CONSOLE} 
{$R *.res} 

uses 
    System.SysUtils, 
    System.Rtti; 

Type 
    // My attribute 
    DemoDataAttribute = class(TCustomAttribute) 
    private 
    FGenerator: String; 
    public 
    constructor Create(Generator: String); 
    published 
    property Generator: string read FGenerator write FGenerator; 
    end; 

    // 
    TSomeType = Class 
    private 
    fPhone: string; 
    published 
    [DemoData('+1800764328')] 
    property Phone: string read fPhone write fPhone; 
    End; 

    // 
    TMegaSuperClass = Class 
    Function Go<T: Class, constructor>: T; 
    End; 

Procedure Test; 
var 
    LMsc: TMegaSuperClass; 
    New: TSomeType; 
Begin 
    LMsc := TMegaSuperClass.Create; 
    try 
    New := LMsc.Go<TSomeType>; 
    Writeln('New.Phone: ' + New.Phone); 
    finally 
    LMsc.Free; 
    // New.Free; 
    end; 
End; 

{ DemoDataAttribute } 

constructor DemoDataAttribute.Create(Generator: String); 
begin 
    FGenerator := Generator; 
end; 

{ TMegaSuperClass } 

function TMegaSuperClass.Go<T>: T; 
var 
    LContext: TRttiContext; 
    LClass: TRttiInstanceType; 
    LProp: TRttiProperty; 
    LAttr: TCustomAttribute; 
    LField: TRttiField; 
begin 
    // Init Rtti 
    LContext := TRttiContext.Create; 
    LClass := LContext.GetType(T) as TRttiInstanceType; 
    Writeln('LClass: ' + LClass.ToString); 
    // Result 
    Result := T.Create; 
    for LProp in LClass.GetProperties do 
    begin 
    Writeln('LProp: ' + LProp.ToString); 
    for LAttr in LProp.GetAttributes do 
    begin 
     Writeln('LAttr: ' + LAttr.ToString); 
     if LAttr is DemoDataAttribute then 
     Begin 
     Writeln('Attr value: ' + DemoDataAttribute(LAttr).Generator); 
     // How write value? 
     LProp.SetValue(@Result, DemoDataAttribute(LAttr).Generator); 
     End; 
    end; 
    end; 
end; 

begin 
    try 
    { TODO -oUser -cConsole Main : Insert code here } 
    Test; 
    Readln; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 

end. 

コンソール出力:

TSomeType
プロパティ電話:文字列
DemoDataAttribute
値:1800764328
電話:このように

答えて

3

LProp.SetValue(Pointer(Result), DemoDataAttribute(LAttr).Generator); 

SetValueの最初の引数はInstance: Pointerと宣言されています。クラス参照は単にインスタンスへのポインタです。これはあなたが望むものです。

+1

「ポインタ」へのキャストは必要ですが、今は確認できません。 –

+0

キャストが必要です(別途コンパイルされません)。また、次のようにキャストすることもできます: 'TObject(Result)'とそれも機能します。コンパイラがジェネリックの現在の制約(クラスやコンストラクタの制約はTObjectの子孫を暗示すべきではないのですか?)を考慮して、そのようなキャストが必要な理由を私は本当に理解できません。 –

関連する問題