德尔福:如何设置使用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;
阵列增强被实现为
The array augmentation is implemented as
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,这是确认的索引出界-exception我在尝试设置任何时候该数组中的元素(通过 ArrValue.SetArrayElement(I,值);
)。难道有谁知道我在做什么错在这里? (也许有更好的方法来做到这一点?)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:
//如果堆对象不是共享的(引用计数= 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.
这篇关于德尔福:如何设置使用DynArraySetLength一个RTTI访问的动态数组的长度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!