2009-11-20 63 views
4

如何在運行時設置數組長度? setLength(t.GetProperty('Propertys'),3); ????如何設置delphi 2010的數組長度rtti

unit Unit3; 

    interface 

    uses 
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
     Dialogs, StdCtrls; 

    type 

    TSubProperty = Class 
     private 
     Fitem2: Integer; 
     Fitem1: String; 
     procedure Setitem1(const Value: String); 
     procedure Setitem2(const Value: Integer); 
     published 
     property item1:String read Fitem1 write Setitem1; 
     property item2:Integer read Fitem2 write Setitem2; 
    End; 

    TArraySubPropertys=array of TSubProperty; 

    TmyObject = Class 
     private 
     FPropertys: TArraySubPropertys; 
     procedure SetPropertys(const Value: TArraySubPropertys); 
     published 
     property Propertys:TArraySubPropertys read FPropertys write SetPropertys; 
    End; 


     TForm3 = class(TForm) 
     Button1: TButton; 
     procedure Button1Click(Sender: TObject); 
     private 
     { Private declarations } 
     public 
     { Public declarations } 
     end; 

    var 
     Form3: TForm3; 

    implementation 

    {$R *.dfm} 

    procedure TForm3.Button1Click(Sender: TObject); 
    var 
    myObject:TmyObject; 
    ctx : TRttiContext; 
    t : TRttiType; 
    obj:TObject; 
    begin 
    myObject :=TmyObject.Create; 
    ctx := TRttiContext.Create; 
    t := ctx.GetType(myObject.ClassType); 
    // setLength(t.GetProperty('Propertys'),3); ???????????????????????????????????? 
    obj:= (t.GetProperty('Propertys').PropertyType as TRttiDynamicArrayType).ElementType.AsInstance.MetaclassType.Create; 
    //showmessage(obj.toStirng); --> TSubProperty 
    t.GetProperty('Propertys').getValue(myObject).setArrayElement(0,obj); 

    obj:= (t.GetProperty('Propertys').PropertyType as TRttiDynamicArrayType).ElementType.AsInstance.MetaclassType.Create; 
    t.GetProperty('Propertys').getValue(myObject).setArrayElement(1,obj); 

    obj:= (t.GetProperty('Propertys').PropertyType as TRttiDynamicArrayType).ElementType.AsInstance.MetaclassType.Create; 
    t.GetProperty('Propertys').getValue(myObject).setArrayElement(2,obj); 

{ 
    myObject.Propertys[0] :=TSubProperty.Create; 
    myObject.Propertys[0].item1 :='x'; 
    myObject.Propertys[0].item2 :=1; 

    myObject.Propertys[1] :=TSubProperty.Create; 
    myObject.Propertys[1].item1 :='y'; 
    myObject.Propertys[1].item2 :=2; 


    myObject.Propertys[2] :=TSubProperty.Create; 
    myObject.Propertys[2].item1 :='z'; 
    myObject.Propertys[2].item2 :=3; 


    ShowMessage(myObject.Propertys[2].item1); 

    FreeAndNil(myObject.Propertys[2]); 
    FreeAndNil(myObject.Propertys[1]); 
    FreeAndNil(myObject.Propertys[0]); 
} 
    FreeAndNil(myObject); 

    end; 

    { TSubProperty } 

    procedure TSubProperty.Setitem1(const Value: String); 
    begin 
     Fitem1 := Value; 
    end; 

    procedure TSubProperty.Setitem2(const Value: Integer); 
    begin 
     Fitem2 := Value; 
    end; 

    { TmyObject } 

    procedure TmyObject.SetPropertys(const Value: TArraySubPropertys); 
    begin 
     FPropertys := Value; 
    end; 

    end. 

編輯:

此代碼改變所述陣列的長度,但錯誤的。 是一個隨機值,而不是5(19736192)

procedure TForm3.Button3Click(Sender: TObject); 
var 
myObject:TmyObject; 
ctx : TRttiContext; 
t : TRttiType; 
v:TValue; 
len:Longint; 
p:pointer; 
begin 
    myObject :=TmyObject.Create; 
    ctx := TRttiContext.Create; 
    t := ctx.GetType(myObject.ClassType); 
    V := t.GetField('FPropertys').GetValue(myObject); 
    len:=5; 
    p:=v.GetReferenceToRawData; 
    ShowMessage(inttostr(integer(@myObject.FPropertys))); //19795652 
    ShowMessage(inttostr(integer(p)));     //19795672 
    DynArraySetLength(p,v.TypeInfo,1,@len); 
    t.GetField('FPropertys').SetValue(myObject,v); 
    ShowMessage(inttostr(length(myObject.Propertys))); //array length=19736192 ??? 
end; 

編輯2:

@Robert愛,謝謝你的答覆,但問題仍然存在。 (Embarcadero®Delphi®2010版本14.0.3513.24210)

單擊按鈕2 無效的指針操作。

procedure TForm7.Button2Click(Sender: TObject); 
var 
myObject:TmyObject; 
ctx : TRttiContext; 
t : TRttiType; 
v : Tvalue; 
p : Pointer; 
Len : Longint; 
begin 
    myObject :=TmyObject.Create; 
    ctx := TRttiContext.Create; 
    t := ctx.GetType(myobject.ClassType); 
    V := t.GetProperty('Propertys'); 
    Len := 3; 
    P := V.GetReferenceToRawData; 
    DynArraySetLength(P,V.TypeInfo,1,@Len); // error invalid pointer operation 
    ShowMessage(inttostr(length(myObject.Propertys))); 
end; 
+0

請注意,*屬性*的複數是*屬性*,而不是* propertys *。即使在源代碼中,拼寫也很重要。 – 2009-11-20 15:17:57

+0

@Rob Kennedy,你說得對。定義的第三方類別。 – user215424 2009-11-20 18:43:51

回答

6

您可以使用DynArraySetLength函數。

var 
... 
V : TValue; 
Len : LongInt; 
P : Pointer; 
begin 
    ... 
    V := t.GetProperty('Propertys'); 
    Len := 3; 
    P := V.GetReferenceToRawData; 
    DynArraySetLength(P,V.TypeInfo,1,@Len); 
    ... 
end; 

我在RttiUtils.pas在TArrayElementAdd類使用此方法。

+0

@Robert Love,非常感謝... – user215424 2009-11-20 14:44:03

+0

@Robert Love,DynArraySetLength(V,V.TypeInfo,1,@ Len);不工作。 :( E2033類型的實際和正式的變量參數必須是相同的 – user215424 2009-11-20 18:35:57

+1

我已經修復了這個問題,當我發佈回覆時有點太睡不着覺 – 2009-11-20 21:15:32