この投稿で提案されているように、動的配列の長さを設定したいと思います。2つのクラスTMyClassと関連するTChildClassが次のように定義されています
TChildClass = class
private
FField1: string;
FField2: string;
end;
TMyClass = class
private
FField1: TChildClass;
FField2: Array of TChildClass;
end;
アレイ拡張は次のように実装されます
var
RContext: TRttiContext;
RType: TRttiType;
Val: TValue; // Contains the TMyClass instance
RField: TRttiField; // A field in the TMyClass instance
RElementType: TRttiType; // The kind of elements in the dyn array
DynArr: TRttiDynamicArrayType;
Value: TValue; // Holding an instance as referenced by an array element
ArrPointer: Pointer;
ArrValue: TValue;
ArrLength: LongInt;
i: integer;
begin
RContext := TRTTIContext.Create;
try
RType := RContext.GetType(TMyClass.ClassInfo);
Val := RType.GetMethod('Create').Invoke(RType.AsInstance.MetaclassType, []);
RField := RType.GetField('FField2');
if (RField.FieldType is TRttiDynamicArrayType) then begin
DynArr := (RField.FieldType as TRttiDynamicArrayType);
RElementType := DynArr.ElementType;
// Set the new length of the array
ArrValue := RField.GetValue(Val.AsObject);
ArrLength := 3; // Three seems like a nice number
ArrPointer := ArrValue.GetReferenceToRawData;
DynArraySetLength(ArrPointer, ArrValue.TypeInfo, 1, @ArrLength);
{ TODO : Fix 'Index out of bounds' }
WriteLn(ArrValue.IsArray, ' ', ArrValue.GetArrayLength);
if RElementType.IsInstance then begin
for i := 0 to ArrLength - 1 do begin
Value := RElementType.GetMethod('Create').Invoke(RElementType.AsInstance.MetaclassType, []);
ArrValue.SetArrayElement(i, Value);
// This is just a test, so let's clean up immediatly
Value.Free;
end;
end;
end;
ReadLn;
Val.AsObject.Free;
finally
RContext.Free;
end;
end.
D2010 RTTIを初めて使用するため、エラーはクラスインスタンスからのArrValueの取得に依存する可能性があると思われましたが、その後WriteLn
は「TRUE」と出力されるため、除外しました。ただし、残念ながら、同じWriteLn
レポートでArrValueのサイズが0であることが報告されています。これは、「範囲外のインデックス」によって確認されます。これは、配列内の要素のいずれかを設定しようとしたときに発生する例外です(からArrValue.SetArrayElement(i, Value);
)。私がここで間違っていることを誰かが知っていますか?(または、これを行うためのより良い方法があるかもしれませんか?)TIA!