Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   RTTI und Array of Record (https://www.delphipraxis.net/192269-rtti-und-array-record.html)

baumina 4. Apr 2017 14:41

RTTI und Array of Record
 
Folgende Klassen und Records habe ich (Code stark gekürzt):

Delphi-Quellcode:
  TAcField = class
  private
    FFieldName : String;
    FFieldValue : String;
  public
    constructor Create(AFieldName : String);
    property FieldName : String read FFieldName;
    property FieldValue : String read FFieldValue write FFieldValue;
  end;

  TAcArticle = record
    Art_Desc : TAcField;
    Art_Qty : TAcField;
  end;

  TAcArticleArray = Array[1..5] of TAcArticle;

  TAc = class
  private
    FHeader  : TAcField;
    FVersion : TAcField;
    FArticles : TAcArticleArray;
    procedure FreeFields;
  end;

procedure TAc.FreeFields;
type
  PAcField       = ^TAcField;
  PAcArticleArray = ^TAcArticleArray;

var
  LCtx       : TRttiContext;
  LField     : TRttiField;
  LArrayField : TRttiField;
  pField     : PAcField;
  pArray     : PAcArticleArray;
  i          : Integer;

begin
  for LField in LCtx.GetType(Self.ClassInfo).GetDeclaredFields do
  begin
    if lfield.getvalue(self).Typeinfo.Name = 'TAcField' then
    begin
      pField := PAcField(NativeInt(Self) + lField.Offset);
      TAcField(pField^).Free;
      LField.SetValue(self, nil);
    end;
    if lfield.getvalue(self).Typeinfo.Name = 'TAcArticleArray' then
    begin
      pArray := PAcArticleArray(NativeInt(Self) + lField.Offset);
      for i := Low(TAcArticleArray(pArray^)) to High(TAcArticleArray(pArray^)) do
      begin
// das funktioniert zwar, aber möchte ich auch noch abstrahieren
//      TAcArticleArray(pArray^)[i].Art_Desc.Free;
//      TAcArticleArray(pArray^)[i].Art_Qty.Free;
//    end;
// alle meine Versuche waren bislang ohne Erfolg:
        for LArrayField in LCtx.GetType(????TAcArticleArray(pArray^)[i]????).AsRecord.GetFields do
        begin
          pField := PAcField(NativeInt(LArrayField) + LArrayField.Offset);
          TAcField(pField^).Free;
          LArrayField.SetValue(LArrayField, nil);
        end;
      end;
    end;
  end;
end;
Wie schaffe ich es alle Felder im Array freizugeben?

Zacherl 4. Apr 2017 15:03

AW: RTTI und Array of Record
 
Darf man fragen, warum du hierfür RTTI verwendest? Sieht für mich so aus, als ob das Problem ohne RTTI viel einfacher und performanter zu lösen wäre.

baumina 4. Apr 2017 15:12

AW: RTTI und Array of Record
 
Wie oben schon geschrieben, habe ich alles stark gekürzt. Tatsächlich handelt es sich um ca. 200 Felder, die nicht nur freigegeben werden müssen, sondern auch validiert uvm. werden müssen. Diese Klasse wird sicherlich im Laufe der Zeit immer wieder neue Felder bekommen, oder vorhandene verändert, so dass ich mir über RTTI sicherlich am wenigsten Fehlerquellen beim Programmieren einhandeln kann.

Stevie 4. Apr 2017 15:47

AW: RTTI und Array of Record
 
Ohne Anspruch auf Vollständigkeit, Fehlerfreiheit oder besondere Performance:

Delphi-Quellcode:
procedure FinalizeInstance(p: Pointer; typeInfo: PTypeInfo);
var
  ctx: TRttiContext;
  f: TRttiField;
  fieldType: TRttiType;
  i: Integer;
  arrayType: TRttiArrayType;
  elementType: TRttiType;
  obj: ^TObject;
begin
  for f in ctx.GetType(typeInfo).GetDeclaredFields do
  begin
    fieldType := f.FieldType;
    case fieldType.TypeKind of
      tkRecord:
      begin
        FinalizeInstance(Pointer(PByte(p) + f.Offset), fieldType.Handle);
        FinalizeRecord(Pointer(PByte(p) + f.Offset), fieldType.Handle);
      end;
      tkArray:
      begin
        arrayType := TRttiArrayType(fieldType);
        elementType := arrayType.ElementType;
        // handle only one dim
        for i := 0 to arrayType.TotalElementCount - 1 do
          FinalizeInstance(Pointer(PByte(p) + f.Offset + (i * elementType.TypeSize)), elementType.Handle);
      end;
      tkClass:
      begin
        obj := Pointer(PByte(p) + f.Offset);
        FreeAndNil(obj^);
      end;
    end;
  end;
end;

baumina 6. Apr 2017 09:50

AW: RTTI und Array of Record
 
Klasse, ganz herzlichen Dank!


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf