views:

500

answers:

4

how to set array length in runtime ? setLength(t.GetProperty('Propertys'),3); ????

 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.
+4  A: 

You can use the DynArraySetLength Function.

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

I use this method in my RttiUtils.pas in the TArrayElementAdd class.

Robert Love
@Robert Love , thank you very much...
@Robert Love , DynArraySetLength(V,V.TypeInfo,1,@Len); not working. :(E2033 Types of actual and formal var parameters must be identical
I have fixed the problem, was a bit too sleeply when I posted the reply.
Robert Love
A: 

DynArraySetLength(V,V.TypeInfo,1,@Len);

[DCC Error] Unit7.pas(77): E2033 Types of actual and formal var parameters must be identical

sadettinpolat
A: 

@Robert Love, thank you for reply but problem continues. (Embarcadero® Delphi® 2010 Version 14.0.3513.24210 )

click button2 invalid pointer operation.

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;
What line of code generates th Invalid Pointer operation?
Robert Love
The line of the error --> DynArraySetLength(P,V.TypeInfo,1,@Len);
A: 

This code changes the length of the array , but wrong. Is a random value instead of 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;