Delphi:如何使用DynArraySetLength设置RTTI访问的动态数组的长度? [英] Delphi: how to set the length of a RTTI-accessed dynamic array using DynArraySetLength?
问题描述
我想设置动态数组的长度,如这篇文章。我有两个类TMyClass和相关的TChildClass定义为
I'd like to set the length of a dynamic array, as suggested in this post. I have two classes TMyClass and the related TChildClass defined as
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,这是通过Index out of bounds确认的 - 在尝试设置任何数组中的元素(通过 ArrValue.SetArrayElement(i,Value);
)。有人知道我在这里做错了吗? (或者也许有更好的方法来做这个?)TIA!
Being new to D2010 RTTI, I suspected the error could depend on getting ArrValue from the class instance, but the subsequent WriteLn
prints "TRUE", so I've ruled that out. Disappointingly, however, the same WriteLn
reports that the size of ArrValue is 0, which is confirmed by the "Index out of bounds"-exception I get when trying to set any of the elements in the array (through ArrValue.SetArrayElement(i, Value);
). Do anyone know what I'm doing wrong here? (Or perhaps there is a better way to do this?) TIA!
推荐答案
动态数组是一件很棘手的工作。他们是引用计数,DynArraySetLength中的以下注释应该解释问题:
Dynamic arrays are kind of tricky to work with. They're reference counted, and the following comment inside DynArraySetLength should shed some light on the problem:
//如果堆对象不共享(ref count = 1 ),只是调整大小。否则,我们复制一个副本
// If the heap object isn't shared (ref count = 1), just resize it. Otherwise, we make a copy
您的对象持有一个引用,而TValue也是这样。另外,GetReferenceToRawData给你一个指向数组的指针。您需要说 PPointer(GetReferenceToRawData)^
以获取实际数组传递给DynArraySetLength。
Your object is holding one reference to it, and so is the TValue. Also, GetReferenceToRawData gives you a pointer to the array. You need to say PPointer(GetReferenceToRawData)^
to get the actual array to pass to DynArraySetLength.
已经得到了,你可以调整大小,但你留下了一个副本。然后你必须将它重新设置到原始的数组上。
Once you've got that, you can resize it, but you're left with a copy. Then you have to set it back onto the original array.
TValue.Make(@ArrPointer, dynArr.Handle, ArrValue);
RField.SetValue(val.AsObject, arrValue);
总而言之,使用列表而不是数组可能要简单得多。使用D2010,您可以使用Generics.Collections,这意味着您可以使用 TList< TChildClass>
或 TObjectList< TChildClass>
并具有列表类的所有好处,而不会失去类型安全性。
All in all, it's probably a lot simpler to just use a list instead of an array. With D2010 you've got Generics.Collections available, which means you can make a TList<TChildClass>
or TObjectList<TChildClass>
and have all the benefits of a list class without losing type safety.
这篇关于Delphi:如何使用DynArraySetLength设置RTTI访问的动态数组的长度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!