2016-07-30 13 views
3

Ich habe eine Klasse mit vielen numerischen Feldern, die Anzahl der Felder wächst mit der Projektentwicklung, also wäre es schön, eine Möglichkeit zu haben, alle Felder zurückzusetzen, egal wie viele in Zukunft hinzugefügt werden.Delphi: Wie kann ich alle Klassenfelder auf Null zurücksetzen?

TParams = class 
    public 
    defined: boolean; 
    FirstValue:    byte; // reset from here 
    A0:  single; 
    A1:  single; 
    H1:  TPoint; 
     // ............... 
    A100:  single; 
    LastValue:    byte; // to here 
    procedure Reset; 
    end; 

Die einzige Idee in den Sinn kommt, ist 2 Felder einfügen: vor und nach dem Block, der reseted werden sollte, und verwenden FillMemory:

procedure TParams.Reset; 
begin 
    FillMemory(@FirstValue, Integer(@LastValue)-Integer(@FirstValue),0); 
end; 

Gibt es eine bessere Art und Weise? (Im mit Delphi 7)

+2

Alle Felder in einen Datensatz einfügen und den Datensatz auf Null stellen. Benutze keinen hässlichen Hack wie diesen. –

+1

Die Nullsetzung wird keine "verwalteten" Mitglieder finalisieren. Wenn nur numerische Felder vorhanden sind, ist die Nullsetzung in Ordnung. –

Antwort

6

David Heffernan es schon gesagt: was Sie tun, ein hässlich hacken und nicht sehr sauber. Er gab auch den Hinweis: Drehen Sie Ihre numerische Felder in einem Datensatz:

type 
    TParams = class 
    public 
    Defined: Boolean; 
    Numbers: record 
     A0: Single; 
     A1: Single; 
     H1: TPoint; 
     A100: Single; 
    end; 
    procedure Reset; 
    end; 

Nun ist es sehr einfach, können Sie Reset indem Sie folgendermaßen vorgehen:

procedure TParams.Reset; 
begin 
    FillChar(Numbers, SizeOf(Numbers), 0); 
end; 

Ein einfacher Test:

procedure Test; 
var 
    P: TParams; 
begin 
    P := TParams.Create; 
    try 
    Writeln(Format('%f %f (%d, %d) %f', [P.Numbers.A0, P.Numbers.A1, P.Numbers.H1.X, P.Numbers.H1.Y, P.Numbers.A100])); 
    P.Numbers.A0 := 1.0; 
    P.Numbers.A1 := 2.0; 
    P.Numbers.H1 := Point(11, 22); 
    P.Numbers.A100 := 77.0; 
    Writeln(Format('%f %f (%d, %d) %f', [P.Numbers.A0, P.Numbers.A1, P.Numbers.H1.X, P.Numbers.H1.Y, P.Numbers.A100])); 
    P.Reset; 
    Writeln(Format('%f %f (%d, %d) %f', [P.Numbers.A0, P.Numbers.A1, P.Numbers.H1.X, P.Numbers.H1.Y, P.Numbers.A100])); 
    finally 
    P.Free; 
    end; 
end; 

Dies erzeugt die folgende Ausgabe:

0.00 0.00 (0, 0) 0.00 
1.00 2.00 (11, 22) 77.00 
0.00 0.00 (0, 0) 0.00 

Alternativ können Sie folgendes tun:

TNumbers = record 
    A0: Single; 
    A1: Single; 
    H1: TPoint; 
    A100: Single; 
    end; 

    TParams = class 
    public 
    Defined: Boolean; 
    Numbers: TNumbers; 
    procedure Reset; 
    end; 

Für die mit einer Version mit Generika (Ich weiß, Sie sind mit Delphi 7, die keine Generika, aber wie auch immer, für die anderen), dass Wille vereinfachen Reset ein wenig:

procedure TParams.Reset; 
begin 
    Numbers := Default(TNumbers); 
end; 

Default hat den Vorteil, dass es richtig abschließen wird und den Datensatz initialisieren, falls es verwalteten Typen (Strings, Schnittstellen, etc.) darin.

+0

Danke! Ich wusste, dass Fiedls in Schallplatten gepackt werden können, nur weil es eine Möglichkeit gibt, das nicht zu tun. Jetzt weiß ich, dass es keinen anderen Weg gibt :) –

+1

Ich stimme zu, dass es nicht bequemer wäre, sie in einen Datensatz aufzunehmen rufen Sie sie sofort als 'P.A0' usw. anstelle von' P.Numbers.A0' auf. Aber abgesehen davon, dass alle Felder separat initialisiert werden (kein großes Problem, wenn es nur wenige sind, obwohl Sie vergessen könnten, eins zu setzen, wenn Sie ein Feld hinzufügen), ist der Datensatz die einzige saubere Lösung. Und wenn Sie ein Upgrade auf eine moderne Version von Delphi durchführen können, verwenden Sie die Option 'Default' anstelle von' ZeroMemory' oder 'FillChar' oder ähnlichem. –

+0

FWIW, anstatt Marker * Bytes * wie FirstValue und LastValue zu verwenden, hätten Sie zwei leere Datensätze verwenden können ("FirstValue: record end;"). ;-) Aber ehrlich gesagt, ist es die saubere Lösung, die Nonnen in ihre eigenen Aufzeichnungen zu bringen. –

2

In einigen eingeschränkten Szenarien wie Sie Ihren Fall mit TParams ist, ein Aufruf an InitInstance sollte es tun:

procedure TParams.Reset; 
begin 
    InitInstance(Self); 
end; 
+2

Würde 'InitInstance' nicht aufrufen, wird sein' definiertes' Feld wieder auf 'False' gesetzt? OP versucht nicht, alle Klassenfelder zurückzusetzen, sondern nur einige von ihnen. – SilverWarior

+2

@SilverWarior, ja, würde es. Ich weiß nicht, ob dies gewünscht ist. Ich beziehe mich nur auf den Teil "um alle Felder zurücksetzen zu können" der Frage. Übrigens, es wird auch fehlschlagen, wenn Felder mit verwalteten Typen vorhanden sind. –

Verwandte Themen