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.

EDIT:

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;

EDIT 2:

@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;
2
  • Please note that the plural of property is properties, not propertys. Spelling counts, even in source code. Commented Nov 20, 2009 at 15:17
  • @Rob Kennedy, You are right. defined class of third parties. Commented Nov 20, 2009 at 18:43

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

3 Comments

@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.
According to RTTI Dynamic array TValue Delphi 2010, the correct answer would be DynArraySetLength(PPointer(V.GetReferenceToRawData)^,V.TypeInfo,1,@Len);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.