Delphi: how to set the length of a RTTI-accessed dynamic array using DynArraySetLength?

不打扰是莪最后的温柔 提交于 2019-12-01 20:36:57

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:

// If the heap object isn't shared (ref count = 1), just resize it. Otherwise, we make a copy

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);

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.

I think you should define the array as a separate type:

TMyArray = array of TMyClass;

and use that.

From an old RTTI based XML serializer I know the general method that you use should work (D7..2009 tested):

procedure TXMLImpl.ReadArray(const Name: string; TypeInfo: TArrayInformation; Data: Pointer; IO: TParameterInputOutput);
var
  P: PChar;
  L, D: Integer;
  BT: TTypeInformation;
begin
  FArrayType := '';
  FArraySize := -1;
  ComplexTypePrefix(Name, '');
  try
    // Get the element type info.
    BT := TypeInfo.BaseType;
    if not Assigned(BT) then RaiseSerializationReadError; // Not a supported datatype!
    // Typecheck the array specifier.
    if (FArrayType <> '') and (FArrayType <> GetTypeName(BT)) then RaiseSerializationReadError;
    // Do we have a fixed size array or a dynamically sized array?
    L := FArraySize;
    if L >= 0 then begin
      // Set the array
      DynArraySetLength(PPointer(Data)^,TypeInfo.TypeInformation,1,@L);
      // And restore he elements
      D := TypeInfo.ElementSize;
      P := PPointer(Data)^;
      while L > 0 do begin
        ReadElement(''{ArrayItemName},BT,P,IO); // we allow any array item name.
        Inc(P,D);
        Dec(L);
      end;
    end else begin
      RaiseNotSupported;
    end;
  finally
    ComplexTypePostfix;
  end;
end;

Hope this helps..

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!