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

后端 未结 2 776
你的背包
你的背包 2021-01-21 00:41

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         


        
相关标签:
2条回答
  • 2021-01-21 01:19

    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.

    0 讨论(0)
  • 2021-01-21 01:25

    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..

    0 讨论(0)
提交回复
热议问题