2016-05-04 8 views
4

Ich arbeite an der Standard-Datenklasse unserer Software. Hier ein minimales Beispiel für den aktuellen Stand:Zugriff auf dynamisches Array mit Aufzählungstyp

TDataOne = (Width, Length, Height); 
    TDataTwo = (Diameter, Weight); 

    TDatStruct = class; 

    TDatSubStructOne = class(TDatStruct) 
    public 
     myData : array[TDataOne] of double; 
     procedure writeToFile(AFileName : string); 
    end; 
    TDatSubStructTwo = class(TDatStruct) 
    public 
     myData : array[TDataTwo] of double; 
     procedure writeToFile(AFileName : string); 
    end; 

Um Coderedundanz zu reduzieren Ich mag würde eine Datenstruktur mit einer gemeinsamen Schreibfunktion in TDatStruct begreifen. Die Herausforderungen (zumindest für mich als Amateur) sind:

  1. mydata ist von variabler Größe in Abhängigkeit von der substruct und basiert auf verschiedenen Aufzählungstypen
  2. Ich mag noch mydata mit einem Aufzählungstyp in dem Unter structs zugreifen
  3. ich will nicht wegen der Anzahl der verschiedenen Arrays in der realen Code die Unterstrukturdaten als Parameter an die gemeinsame Schreibfunktion passieren

die einzige Idee (unter Vernachlässigung von Punkt 3) ich habe passieren die Array-Daten von die Unterstruktur mit dem gemeinsamen Schreibvorgang als offene Array-Parameter wie:

writeToFile(AFileName : string; writeData : array of double); 

Gibt es eine Möglichkeit ein dynamisches Array mit einem Aufzählungstyp oder einem virtuellen numerischen Array zu kombinieren? Oder bin ich komplett auf dem falschen Weg?

+0

Verwenden Sie in Ihren Parameterdefinitionen immer 'const' wenn möglich. – Johan

+0

Möchten Sie möglicherweise auch die Dateien lesen? Dann müssten Sie identifizieren, welche Klasse folgende Doppelungen in der Datei darstellen, nein? –

+0

@Johan: Danke, das werde ich mir merken! – SiD

Antwort

4

mydata ist von variabler Größe in Abhängigkeit von der substruct und basiert auf verschiedenen Aufzählungstypen

Delphi hat die intrinsischen Funktionen Low und High
Sie brauchen nicht die Größe des Arrays zu kennen.

Ich möchte noch mydata mit einem Aufzählungstyp in den Unter structs

Verwenden Sie die succ und pred intrinsische Methoden durch die Aufzählung gehen zuzugreifen.

Ich will nicht die Unterstrukturdaten als Parameter an die gemeinsamen Schreibfunktion zu übergeben, da die Anzahl der verschiedenen Arrays in dem realen Code

Alle Ihre Arrays gleich aussehen zu mir. .. Sie sind einfach array of double, wenn auch mit einer anderen Anzahl von Elementen.

Sie können writeToFile implementieren wie so:

procedure writeArrayToFile(const AFileName : string; const writeData : array of double); 
var 
    i: integer; 
begin 
    for i:= low(writeData) to High(writeData) do begin 
    WriteADoubleToFile(AFilename, writeData[i]); 
    end; {for i} 
end; 

Beachten Sie die Verwendung von const, wenn Sie diese nicht verwenden das Array auf den Stack kopiert werden, was zu großen Verzögerungen bei großen Arrays.

Wenn das Array ein Datenelement der Klasse ist, dann können Sie einfach den Code schreiben, wie so:

procedure TDatStruct.writeToFile(const AFileName : string); 
begin 
    WriteArrayToFile(FileName, GetMyData^); 
end; 

Beachten Sie, dass, weil die Elternklasse TDatStruct hat tatsächlich keine Daten innerhalb haben, Sie‘ Ich muss eine virtuelle Funktion schreiben, die diese Daten bekommt.

type 
    TMyArray = array[0..0] of double; 
    PMyArray = ^TMyArray; 

..... 
TDatStruct = class 
protected 
    function GetMyData: PMyArray; virtual; abstract; 
public 
    procedure WriteToFile(const Filename: string); //no need for virtual 
end; 

Die open array parameter der WriteArrayToFile wird das Problem für Sie beheben.

beachten, dass der Array-Parameter in writeToFile ist eine „offene Array-Parameter“, dann ist dies sowohl statische als auch dynamische Felder akzeptieren.

Wenn Sie verschiedene Arten von Arrays (Doppel/string usw.).
Verwenden Sie dann eine generische Methode.

Gibt es eine Möglichkeit, ein dynamisches Array mit einem Aufzählungstyp oder einem virtuellen Aufzählungsfeld zu kombinieren? Oder bin ich komplett auf dem falschen Weg?

Ein dynamisches Array hat eine variable Anzahl von Elementen.
Sie nicht indizieren kann es direkt eine Aufzählung verwenden.
Allerdings können Sie den aufgezählten Wert in eine ganze Zahl übersetzen die Ord intrinsische Funktion.
Es funktioniert auch mit mehr als 256 Werte für Aufzählungen. Die Dokumentation ist falsch, es werden Bytes, Wörter oder Kardinale nach Bedarf zurückgegeben.

function FixedArrayToDynamicArray(const input: array of double): TArray<double>; 
begin 
    //translate a fixed array to a dynamic array. 
    SetLength(Result, High(input)); 
    Move(input[0], Result[0], SizeOf(Double) * High(input)); 
end; 

pre-Generika der Code wird:

type 
    TDoubleArray = array of double; 

function FixedArrayToDynamicArray(const input: array of double): TDoubleArray; 
... same from here on. 
+0

Ich denke, die Funktion GetMyData ist genau das, wonach ich suche. Ich hatte das Problem, eine Referenz für eine Variable zu erhalten, die nur als Enumerationsarray im Nachkommen definiert ist. Sobald ich es erfolgreich mit meinem Code probiert habe, werde ich als gelöst markieren! – SiD

+0

Wenn ich die Funktion 'GetMyData' als' Result: = @ myData' implementiere, habe ich das Problem, dass 'High (writeData) 'in der Funktion' writeArrayToFile' 0 zurückgibt und ich nur auf das erste Element des Arrays zugreifen kann. – SiD

+0

@Sid, ja, Das Ergebnis von GetMyData hat nur ein Element. Hmm, du musst 'FixedArrayToDynamicArray' verwenden oder 'GetMyData' gibt die Anzahl der Elemente in einem' out'-Parameter zurück. – Johan

0

Es gibt viele verschiedene Ansätze, ist es schwierig zu sagen, was am besten in Ihrer Situation ist.

Sicherlich WriteToFile sollte in TDatStruct als abstrakte eingeführt werden:

TDatStruct = class 
    public 
    procedure WriteToFile(AFileName: string); virtual; abstract; 

und Nachkommen sollte es anders implementieren:

TDatStructOne = class (TDatStruct) 
    ... 
    public 
    procedure WriteToFile(AFileName: string); override; 

in einer solchen Art und Weise, Sie Objekt der Klasse TDatStruct haben kann, wo eigentlich sei TDatStructOne oder TDatStructTwo, aber der Code, der es benutzt, muss nicht "wissen", womit es sich beschäftigt: grundlegender Polymorphismus.

In einem solchen Fall, dass Sie viel Freiheit zu Datentypen haben Sie in jeder Klasse zum Speichern von Informationen verwenden, können Implementierungen variieren. Am einfachsten wäre:

TDatStructOne = class (TDatStruct) 
    public 
    Width: Double; 
    Length: Double; 
    Height: Double; 
    procedure WriteToFile(AFileName: string); override; 
end; 

TDatStructTwo = class (TDatStruct) 
    public 
    Diameter: Double; 
    Weight: Double; 
    procedure WriteToFile(AFileName: string); override; 
end; 

und in WriteToFile jeweils Nachkommen macht seinen Job.

durch Ihre Herausforderungen Also:

  1. Sie Daten variabler Größe haben, nicht notwendigerweise Array von Double, was Sie wollen (Strings, Zahlen, Mengen etc.)
  2. Sie haben praktisch bekam Zugriff auf alle diese Felder, solange Sie Objekte der Klasse TDatStructOne oder TDatStructTwo (konkrete Klassen) haben.
  3. Es gibt kein gewöhnliches Schreibverfahren. Stattdessen haben Sie eine gemeinsame "Schreibschnittstelle". Sie schreiben obj.SaveToFile(FileName) und es wird entsprechend gespeichert.
+0

Sie haben das Aufzählungsproblem nicht einmal angesprochen, abgesehen davon, dass Ihr Code nicht funktioniert, weil er ein Array nicht als Parameter akzeptiert. – Johan

+0

@Johan Ich habe das starke Gefühl, dass OP nur mit Arrays arschiert, weil es die einzige Möglichkeit scheint, verschiedene Daten zu speichern, ohne wenn es überall ist, und es wird eine Weile funktionieren, aber dann wird es TDatStructThree, die nicht nur verdoppelt und speichert Das alles wird auseinander brechen. Aber natürlich funktioniert meine "Telepathie" nur in 50% der Fälle, vielleicht irre ich mich hier. –

+0

Ich denke, dass ein Array tatsächlich der richtige Weg ist, um das Problem zu lösen. Sprinkling verlieren verdoppelt herum scheint nicht die richtige Lösung. Und es skaliert nicht. Die Verwendung von Arrays macht die Lösung trivial. – Johan