Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Kann man "X: array of array of const" realisieren? (https://www.delphipraxis.net/82624-kann-man-x-array-array-const-realisieren.html)

Panthrax 16. Dez 2006 16:00


Kann man "X: array of array of const" realisieren?
 
Hallo zusammen.

Ich habe verschiedene Klassen die Objektlisten verwalten. Dabei haben einige Listen Unterlisten. Alle Listen haben gemeinsam, dass Starteinträge zur Programmierzeit bereits feststehen. Ich möchte daher dem Kontruktor diese Starteinträge mit auf den Weg geben. Für die Listen ohne Unterlisten sieht der Kontruktur beispielhaft so aus:
Delphi-Quellcode:
TMyObjectList1 = class(TObjectList)
  ...
  constructor Create(const Items: array of const);
  ...
end;

constructor TMyObjectList1.Create(const Items: array of const);
var
  Index: Integer;
begin
  inherited Create;

  for Index := 0 to High(Items) do
    if Items[Index].VType = vtObject
      then Add(Items[Index].VObject)
      else Exception.Create('Typ des Elements im Array-Parameter kann nicht verarbeitet werden.');
end;
Ich hätte auch gern den Listen mit Unterlisten die Starteinträge dem Konstruktor übergeben; etwa so:
Delphi-Quellcode:
TMyObjectList2 = class(TObjectList)
  ...
  constructor Create(const Items: array of const);
  ...
end;

constructor TMyObjectList2.Create(const Items: array of const);
var
  Index: Integer;
begin
  inherited Create;

  for Index := 0 to High(Items) do
    if Items[Index].VType = {?}...{/?}
      then Add(TMyObjectList1.Create({?}Items[Index]{/?}))
      else Exception.Create('Typ des Elements im Array-Parameter kann nicht verarbeitet werden.');
end;
Das würde es gestatten eine Liste auf höherer Ebene wie folgt zu erzeugen:
Delphi-Quellcode:
MyObjectList:=TMyObjectList.Create([
  [
    [TObject1.Create(...),TObject2.Create(...),TObject3.Create(...)],
    [TObject1.Create(...),TObject4.Create(...),TObject4.Create(...),TObject5.Create(...)]
  ],
  [
    [TObject1.Create(...),TObject6.Create(...)],
    [TObject7.Create(...),TObject7.Create(...)],
    // ...
  ],
  // ...
]);
Momentan ist das Erzeugen und Befüllen der Listen ein Wust aus Variablen, Kontruktoren und Add-Funktionen.

Aber wenn ich versuche ein Array, wie oben gezeigt, als Parameter zu übergeben, teilt mir der Compiler beim ersten Unterelement-Array mit: "Ordinaltyp erforderlich." Gibt es eine Möglichkeit die Unterelement-Arrays sicher als Ordinaltyp zu kaschieren?

Gruß,
Panthrax.

mkinzler 16. Dez 2006 16:09

Re: Kann man "X: array of array of const" realisie
 
Versuchs mal mit inem "ZwischenTyp"

Delphi-Quellcode:
Type
    ConstArray=Array of Const;
   
...
X: Array of ConstArray

Panthrax 16. Dez 2006 16:28

Re: Kann man "X: array of array of const" realisie
 
Soetwas wie
Delphi-Quellcode:
type
  TArrayOfConst = array of const;
kann nicht deklariert werden.

Und, um es gleich vorweg zu nehmen: Auch soetwas hilft nicht weiter:
Delphi-Quellcode:
type
  TArrayOfVariant = array of Variant;
Delphi möchte in jedem Fall beim Unterarray einen Ordinaltyp haben. Eine dreiste Typumwandlung mit Integer(...), TObject(...), Pointer(...) usw. mekert der Compiler auch nur an: "Ungültige Typumwandlung."

Irgendwelche anderen Ideen?

Gruß,
Panthrax.

marabu 16. Dez 2006 18:18

Re: Kann man "X: array of array of const" realisie
 
Hallo Panthrax,

[equote="D7 OH - Topic 'Variante offene Array-Parameter'"]... array of const ist zur Konstruktion array of TVarRec äquivalent. ...[/equote]
daraus schließe ich, dass du die Variable X aus dem Titel deines threads alternativ so deklarieren kannst - ohne dass der Compiler sich beschwert:

Delphi-Quellcode:
var
  X: array of array of TVarRec;
Inwieweit das eine Lösung für dein im Text formuliertes Problem sein kann, habe ich mir noch nicht überlegt.

Grüße vom marabu

Panthrax 17. Dez 2006 09:34

Re: Kann man "X: array of array of const" realisie
 
Zitat:

Zitat von marabu
ohne dass der Compiler sich beschwert:
Delphi-Quellcode:
var
  X: array of array of TVarRec;

Das ist soweit richtig.
Zitat:

Inwieweit das eine Lösung für dein im Text formuliertes Problem sein kann, habe ich mir noch nicht überlegt.
Das Problem ist die Notation: Mit "[...]" kann man einen "array of"-Parameter übergeben aber kein Element eines "array of" im Quelltext notieren; à la "[[...], [...],...]". Der Compiler verlangt als Arrayelement einen Ordinaltyp ("Ordinaltyp erforderlich.").

Deshalb meine Frage: Kann man diese inneren Arrays mit Typen kaschieren, die der Compiler akzeptiert? Mit den Erkenntnissen von oben könnte man die Fragen auch so formulieren: Wie kann man ein "array of" in einem TVarRec unterbringen (damit dieser wiederum als "array of"-Element fungieren kann)?

Eine Notation wie "[[...], [...],...]" würde mir den Quelltext an diesen Stellen ordentlich aufräumen. Wie gesagt, momentan ist das ein "Wust aus Variablen, Kontruktoren und Add-Funktionen", um die Listen mit den Startwerten zu befüllen. Es gibt leider auch keine Regelmäßigkeit unter den Elementen, die ich nutzen könnte, das in eine Schleife zu packen.

Gruß,
Panthrax.

Hawkeye219 17. Dez 2006 11:18

Re: Kann man "X: array of array of const" realisie
 
Hallo Panthrax,

mit einer Hilfsfunktion, welche deine Objekte temporär in eine Liste packt, kommst du vielleicht doch noch ans Ziel:

Delphi-Quellcode:
function NewList (const aItems: array of TObject): TList;
var
  i : Integer;
begin
  Result := TList.Create;
  for i := 0 to High(aItems) do
    Result.Add(aItems[i]);
end;
Da die Liste selbst wieder ein Objekt ist, kannst du die Aufrufe von NewList schachteln:

Delphi-Quellcode:
HandleItems (
  NewList([
    NewList([
      TObject.Create,
      TObject.Create,
      TObject.Create
      ]),
    NewList([
      TObject.Create,
      TObject.Create
      ]),
    NewList([
      TObject.Create,
      TObject.Create,
      TObject.Create,
      TObject.Create
      ])
    ])
  );
Auch wenn das ganze sehr kompakt aussieht, die Lösung birgt Gefahren. Die verarbeitende Routine kann nicht zwischen "normalen" Objekten und Hilfslisten unterscheiden, falls die Objekte selbst von TList abgeleitet sind. Sollte dies notwendig sein, muß auch die Hilfsliste von TList abgeleitet werden, die Überprüfung erfolgt dann mit Hilfe des Operators IS. Weiterhin ist darauf zu achten, daß die temporären Listen wieder freigegeben werden, sonst enstehen Memleaks. Neben diesen Problemen entsteht durch den Aufbau der Listen ein kleiner Overhead, der aber wahrscheinlich vernachlässigt werden kann.


Eine andere Möglichkeit wäre die Verwendung von dynamischen Arrays:

Delphi-Quellcode:
type
  TObjectMatrix = array of array of TObject;

var
  Items : TObjectMatrix;

begin
  SetLength (Items, 3),

  SetLength (Items[0], 3);
  Items[0, 0] := TObject.Create;
  Items[0, 1] := TObject.Create;
  Items[0, 2] := TObject.Create;

  SetLength (Items[1], 2);
  Items[1, 0] := TObject.Create;
  Items[1, 1] := TObject.Create;

  SetLength (Items[2], 4);
  Items[2, 0] := TObject.Create;
  Items[2, 1] := TObject.Create;
  Items[2, 2] := TObject.Create;
  Items[2, 3] := TObject.Create;

  HandleItems (Items);
end;

procedure HandleItems (const aItems: TObjectMatrix);
var
  i, j : Integer;
begin
  for i := 0 to High(aItems) do
    for j := 0 to High(aItems[i]) do
      { verarbeite Objekt an Position (i, j) }
end;
Es ist etwas mehr Schreibarbeit beim Aufruf, aber die oben genannten Probleme werden vermieden.

Gruß Hawkeye

radekj 17. Dez 2006 14:50

Re: Kann man "X: array of array of const" realisie
 
TRY THIS:

Delphi-Quellcode:
type
TConstArray= array of const;

...

//you need this function
function CopyVarRec(const Item: TVarRec): TVarRec;
var
  W: WideString;
begin
  // Copy entire TVarRec first
  Result := Item;

  // Now handle special cases
  case Item.VType of
    vtExtended:
      begin
        New(Result.VExtended);
        Result.VExtended^ := Item.VExtended^;
      end;
    vtString:
      begin
        New(Result.VString);
        Result.VString^ := Item.VString^;
      end;
    vtPChar:
      Result.VPChar := StrNew(Item.VPChar);
    // there is no StrNew for PWideChar
    vtPWideChar:
      begin
        W := Item.VPWideChar;
        GetMem(Result.VPWideChar,
               (Length(W) + 1) * SizeOf(WideChar));
        Move(PWideChar(W)^, Result.VPWideChar^,
             (Length(W) + 1) * SizeOf(WideChar));
      end;
    // a little trickier: casting to string will ensure
    // reference counting is done properly
    vtAnsiString:
      begin
        // nil out first, so no attempt to decrement
        // reference count
        Result.VAnsiString := nil;
        string(Result.VAnsiString) := string(Item.VAnsiString);
      end;
    vtCurrency:
      begin
        New(Result.VCurrency);
        Result.VCurrency^ := Item.VCurrency^;
      end;
    vtVariant:
      begin
        New(Result.VVariant);
        Result.VVariant^ := Item.VVariant^;
      end;
    // casting ensures proper reference counting
    vtInterface:
      begin
        Result.VInterface := nil;
        IInterface(Result.VInterface) := IInterface(Item.VInterface);
      end;
    // casting ensures a proper copy is created
    vtWideString:
      begin
        Result.VWideString := nil;
        WideString(Result.VWideString) := WideString(Item.VWideString);
      end;
    vtInt64:
      begin
        New(Result.VInt64);
        Result.VInt64^ := Item.VInt64^;
      end;
    // VPointer and VObject don't have proper copy semantics so it
    // is impossible to write generic code that copies the contents
  end;
end;

//and you need this function
//CCA = CreateConstArray
function CCA(const Elements: array of const): TConstArray;
var
  I: Integer;
begin
  SetLength(Result, Length(Elements));
  for I := Low(Elements) to High(Elements) do
    Result[I] := CopyVarRec(Elements[I]);
end;

//yours constructor
constructor TMyObjectList2.Create(Items: array of const);

//yours call to constructor

 := TMyObjectList2.Create([
                          CCA([TObject.Create]),
                          CCA([TObject.Create, TObject.Create]),
                          ...
                         ]);
Alles klar ?!

ciao
Radek


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:09 Uhr.

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