Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Create abbrechen (https://www.delphipraxis.net/92039-create-abbrechen.html)

Masterj44 13. Mai 2007 18:52


Create abbrechen
 
Hi Leute,
hab da mal ne Frage

Kann man ein Create abbrechen?

Also ich habe ein Create Methode, die sich bei bestimmten Voraussetzungen selbst mit self.destroy zerstört.

Frage:
1. Ist es so möglich die Instanz zu löschen?
2. Wenn ja, wieso gib die varible die auf die Instanz zeigt nicht nil?

GuenterS 13. Mai 2007 19:10

Re: Create abbrechen
 
Weil Destroy nur das Objekt freigibt und nicht auf Nil setzt. Verwende anstelle dessen doch FreeAndNil.

mkinzler 13. Mai 2007 19:12

Re: Create abbrechen
 
Aber vielleicht wäre es besser es erst garn icht zu erzeugen

Masterj44 13. Mai 2007 19:19

Re: Create abbrechen
 
@ GuenterS FreeandNil klapt nicht da es mit self.destroy zerstört werden muss

Anders geht es leider nicht. Als ich brauch nur eine Methode die mir sagt, dass die Erzeugung des Objekts nicht geklappt hat.

Christian Seehase 13. Mai 2007 19:23

Re: Create abbrechen
 
Moin Master,

wenn sich im Konstruktor eine Konstellation ergibt, die die Instanzierung sinnlos machen könntest Du einfach eine Exception auslösen, so dass die Stelle, die den Konstruktor aufgerufen hat darauf reagieren kann.


Delphi-Quellcode:
type
  TMyClass = class(TObject)
  public
    constructor Create;
  end;

procedure IrgendEine;

var
  tmc : TMyClass;

begin
  try
    tmc := TMyClass.Create;
    try
      // Tu was mit der Instanz
    finally
      FreeAnNil(tmc);
    end;
  except
    // Hier eine passende Meldung ausgeben
  end;
end;

constructor TMyClass.Create;
begin
  inherited;
  if FalscheVoraussetzung then raise Exception.Create('Fehler');
end;

Elvis 13. Mai 2007 20:03

Re: Create abbrechen
 
Zitat:

Zitat von Christian Seehase
wenn sich im Konstruktor eine Konstellation ergibt, die die Instanzierung sinnlos machen könntest Du einfach eine Exception auslösen, so dass die Stelle, die den Konstruktor aufgerufen hat darauf reagieren kann.

Eine Ausnahme im Konstruktor sollte schon zum Freigeben des Objektes führen. Doppeltes Freigeben ist nicht so nett.
Das ist auch der Grund, warum man das Instanzieren vor den berühmt-berüchtigten try-finally-free-Block schreibt.

alzaimar 13. Mai 2007 20:05

Re: Create abbrechen
 
Meiner Meinung nach sollte man keine Konsistenzprüfung in einem Konstruktor vornehmen. Das ist zwar Geschmackssache, aber in meinen Augen durchaus sinnvoll: Beim Erstellen einer Instanz weiss ich noch gar nicht, ob sie später mal konsistenz ist oder nicht (gemäß der Theorie).

Entweder implementiere ich das in einer Class Function und rufe die VOR der Instantiierung auf (praktisch, aber uncool), oder ich prüfe die Konsiszenz über eine stinknormale Methode, die die Eigenschaften, die ich ja (reine Lehre) erst zuweisen muss, naturgemäß bei der Instantiierung noch nicht bekannt sind.

In seltenen Fällen (siehe TFileStream) kann es aber durchaus Sinn machen (bzw. die Tipparbeit erheblich verkürzen und zu lesbarerem Code führen), Eigenschaften in einem Konstruktor zu übergeben und eine Prüfung während der Instantiierung vorzunehmen. Dann wird eine Exception ausgelöst, wie es hier auch schon erwähnt wurde. Es wird -soweit ich weiss- kein Speicher alloziiert, sodaß die Instanz auch nicht freigegeben werden muss.

Jelly 13. Mai 2007 20:07

Re: Create abbrechen
 
Wie Chris schon schrieb, so würd ich das auch lösen. Anstatt einer einfachen Exception würd ich eventuell eine Assertion auslösen. Denn genau dafür sind die da.

Das ist ein typisches Beispiel. Im Construtor der Klasse müssen gewisse Bedingungen erfüllt sein, damit die Klasse überhaupt Sinn macht. z.B. wenn ein Datensatz aus einem Dataset in einer Klasse abgebildet werden soll, so empfiehlt es sich, im constructor den Primary Key des Datensatz anzugeben. Gibt es den nicht, macht eine Instanz eventuell keinen Sinn.

Eine Assertion ist eine Art von exception, die Dir aber bequemerweise aber in der Fehlermeldung auch gleich noch die Zeilennummer in deinem Code ausgibt, in der die Assertion ausgelöst wurde.

Elvis 13. Mai 2007 20:23

Re: Create abbrechen
 
Zitat:

Zitat von alzaimar
Meiner Meinung nach sollte man keine Konsistenzprüfung in einem Konstruktor vornehmen. Das ist zwar Geschmackssache, aber in meinen Augen durchaus sinnvoll: Beim Erstellen einer Instanz weiss ich noch gar nicht, ob sie später mal konsistenz ist oder nicht (gemäß der Theorie).

Jain.

Für stinknormale Klassen, die transiente oder persistente Daten deines Applikationsmodelles halten mag das zutreffen.
Aber es wird immer wieder Klassen geben, die sich immer in einem konsistenten Zustand befinden müssen.
Ein FileStream wäre so ein Fall.

Zitat:

Entweder implementiere ich das in einer Class Function und rufe die VOR der Instantiierung auf (praktisch, aber uncool)...
Klassische Factory, IMHO sogar sehr cool, da de Prüfung vor dem Allozieren von Speicher passieren kann.
Zitat:

, oder ich prüfe die Konsiszenz über eine stinknormale Methode, die die Eigenschaften, die ich ja (reine Lehre) erst zuweisen muss, naturgemäß bei der Instantiierung noch nicht bekannt sind.
Das Zuweisen einzelnener Eigenschaften lässt es aber nicht zu einen konsistenten Zustand zu garantieren.
Änder ich Eigenschaft1 zu "X" wäre meine Instanz vllt ouchy banana und der Setter springt mir ins Gesicht.
Er kann ja nicht wissen, dass ich Eigenschaft2 direkt danach auch "Y" ändern wollte.
Ein Konstruktor, dem beide Werte übergeben werden, und der sie in einer "Transaktion" ändern kann ist hier natürlich vorteilhaft.
Genau wie es oben genannte Factory wäre.
Zitat:

In seltenen Fällen (siehe TFileStream) kann es aber durchaus Sinn machen (bzw. die Tipparbeit erheblich verkürzen und zu lesbarerem Code führen), Eigenschaften in einem Konstruktor zu übergeben und eine Prüfung während der Instantiierung vorzunehmen.
Selten ist Tipparbeit, sondern Konsistenz die Motivation dahinter.
Zitat:

Dann wird eine Exception ausgelöst, wie es hier auch schon erwähnt wurde. Es wird -soweit ich weiss- kein Speicher alloziiert, sodaß die Instanz auch nicht freigegeben werden muss.
Der Konstruktor wird nach NewInstance ausgeführt, also nachdem Speicher reserviert wurde.
In der Kette der einzelnen Calls, die irgendwann zu einer fertigen Instanz führen, wird aber beim Auftreten einer Exception die neue Instanz sofort freigegeben.


Zitat:

Zitat von Jelly
Wie Chris schon schrieb, so würd ich das auch lösen. Anstatt einer einfachen Exception würd ich eventuell eine Assertion auslösen. Denn genau dafür sind die da.
...
Eine Assertion ist eine Art von exception, die Dir aber bequemerweise aber in der Fehlermeldung auch gleich noch die Zeilennummer in deinem Code ausgibt, in der die Assertion ausgelöst wurde.

Au weia.
Assertions sind dafür da deinen Code zu prüfen. Niemals um Dinge zu prüfen, die von außen/ von Benutzern deiner Klasse rein geworfen wurden.
Denn Assertions werden normalerweise im Release ausgeschaltet.

DGL-luke 13. Mai 2007 20:26

Re: Create abbrechen
 
eine assertion so wie "assert(boolean, string)"?

wird die nicht im final build deaktiviert?

//wie elvis sagte.

Jelly 13. Mai 2007 21:13

Re: Create abbrechen
 
Zitat:

Zitat von Elvis
Assertions sind dafür da deinen Code zu prüfen. Niemals um Dinge zu prüfen, die von außen/ von Benutzern deiner Klasse rein geworfen wurden.
Denn Assertions werden normalerweise im Release ausgeschaltet.

Das ist richtig. Aber ich bin im Beispiel davon ausgegangen, dass im final Release die Fehler erkannt sind. Das ist ne Interpretationssache der Frage.

Wenn ich eine Klasse mit TKlasse.Create (123) instanziere anstatt mit TKlasse.Create(124), so fliegt mir die Assertion um die Ohren, und ich kann den Code bereinigen. Nach Testen tritt der Fehler nicht mehr auf, und im Final Release kann ich beruhigt die Assertion ausschalten.

Aber Du hast Recht. Wenn es wirklich um logische Überprüfungen geht, so ist eine Exception die erste Wahl.

Ich bin von ersterem ausgegangen. Wir haben bei uns einige visuelle Klassen, die im Code instaziert werden und im Form dargestellt werden. Und wenn die 30 Instanzen einmal laufen, so wird sich daran auch nie mehr was ändern. Ich kann also während der Entwicklung ALLE Fälle testen, und bin mir demnach sicher, im Final Release werden auch keine Fehler mehr auftreten.

Elvis 13. Mai 2007 21:20

Re: Create abbrechen
 
Schaue mal hier vorbei: madExcept

alzaimar 14. Mai 2007 08:11

Re: Create abbrechen
 
Zitat:

Zitat von Elvis
Das Zuweisen einzelnener Eigenschaften lässt es aber nicht zu einen konsistenten Zustand zu garantieren.
Änder ich Eigenschaft1 zu "X" wäre meine Instanz vllt ouchy banana und der Setter springt mir ins Gesicht.
Er kann ja nicht wissen, dass ich Eigenschaft2 direkt danach auch "Y" ändern wollte.
Ein Konstruktor, dem beide Werte übergeben werden, und der sie in einer "Transaktion" ändern kann ist hier natürlich vorteilhaft.
Genau wie es oben genannte Factory wäre.

Wenn mein Konstruktor knallen könnte, überlege ich mir sehr genau, ob ich eine Konsistenzprüfung dort einbaue. Ich bevorzuge liebe eine 'Prepare'-Methode, die die Eigenschaften prüft, oder lass das von der Methode ausführen, die konsistente Eigenschaften voraussetzt. Um Eigenschaften konsistent zu setzen, würde ich sie logisch zusammenfassen: Entweder als Klasse oder Record. Wenn das noch Overkill ist, dann schreibe ich mir eine 'Set'-Methode à la 'SetBounds'.

Ein TFileStream z.B. hätte man auch analog zur 'AssignFile/ReSet'-Metapher implementieren können: Der Konstruktor entspräche dann dem 'AssignFile': Nur müsste man dann eine Zeile mehr schreiben.

Elvis 14. Mai 2007 09:34

Re: Create abbrechen
 
Zitat:

Zitat von alzaimar
Wenn mein Konstruktor knallen könnte, überlege ich mir sehr genau, ob ich eine Konsistenzprüfung dort einbaue. Ich bevorzuge liebe eine 'Prepare'-Methode, die die Eigenschaften prüft, oder lass das von der Methode ausführen, die konsistente Eigenschaften voraussetzt. Um Eigenschaften konsistent zu setzen, würde ich sie logisch zusammenfassen: Entweder als Klasse oder Record. Wenn das noch Overkill ist, dann schreibe ich mir eine 'Set'-Methode à la 'SetBounds'.

Ein TFileStream z.B. hätte man auch analog zur 'AssignFile/ReSet'-Metapher implementieren können: Der Konstruktor entspräche dann dem 'AssignFile': Nur müsste man dann eine Zeile mehr schreiben.

Solange man sich wirklich Gedanken macht über den Zustand eines Objektes, sollte es kein Richtig & Falsch geben.
Dein Weg wäre sicherlich genauso OK, wie ein anderer. Ich selbst mag es auch lieber parameterlose Konstruktoren zu haben und solche Dinge über Instanzmethoden zu lösen. Nur dadurch kann man überhaupt erst Abtraktionen und Interfaces benutzen.


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

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