Re: ersetzt try..except begin..end?
Zitat:
Wir wissen: ExceptObject ist eine globale Variable. Ist sie auch eine Threadeigene globale Variable -> threadvar ? Wenn nicht kann innerhalb deiner verschachtelten IF Abfragen das ExceptObject als globale Variable durch eine Exception innerhalb eines parallelen Threads verändert werden. Man sollte also wirklich
Delphi-Quellcode:
benutzen. In diesem Moment verhält sich das on E: Exception do wie ein with Variable do Anweisung. Der Compiler wird dann in der lokalen Variable E das aktuelle Exception Object zur Verfügung halten, statt bei jeder IF Abfrage auf ein globales Object zuzugreifen. Davon abgesehen ist das SEH unter Windows Stackbasiert und mit der Abfrage on E: Exception do greifen wir nur auf diesen Stack und damit Threadbezogen auf das einzigste gültige Exception Object zu. Die globale Variable ExceptObject ist also eher eine Krücke damit bestimmte Objekte wie TApplication ein eigene Handling von Exception machen können.
try
except on E: Exception do if E is EAbort then ... else if E is EInOutError then ... else reraise; end; Gruß Hagen |
Re: ersetzt try..except begin..end?
@messie: Weil der Konstruktor fehlschlagen kann, und dann wäre da nichts zum freigeben. Weiterhin stimmt der Kontext nicht: Der Try..Finally-Block soll ja gerade die Verwendung des OPbjektes schützen und nicht die Instantiierung selbst.
Richtig wäre es so:
Delphi-Quellcode:
@NegaH: Ich mag es aber in grün lieber:
Try
Obj := TMyObect.Create; Try Obj.Foobar Finally Obj.Free Finally Showmessage('Ach Du scheisse, noch nich mal Create funzt.') End;
Delphi-Quellcode:
Try
... Except On E:EThisException Do Begin HandleThisException(E); End; On E:EThatException Do Begin HandleThatException (E); End; On E:Exception Do Begin HandleAnyOtherException (E); End; End; |
Re: ersetzt try..except begin..end?
@Messie:
Zitat:
Erst nachdem der Konstruktor erfolgreich zurückkehrt. Und was würde passieren wenn der Konstruktor eine Exception auslösst ? Zb. wegen's Speichermangel oä. ? Dann würden wir sofort im finally end; Block landen. Ist dann die Variable Object wirklich initialisert wurden ? Nein, in Object würde irgendwas stehen, also vorherige Daten aus dem Stack oder einem CPU Register. Wozu führt dies ? Das bei Object.Free; wir ein Object freigeben würden das garnicht also solches existent ist. Nur wenn Object durch dummen Zufall nil =$00000000 wäre würde es keine Zugriffsveretzung geben. Dieser Fall tritt mit exakt 1/2^32 Wahrscheinlichkeit ein, also sehr unwahrscheinlich. Gruß Hagen |
Re: ersetzt try..except begin..end?
@Alzaimar:
Zitat:
Delphi-Quellcode:
1.) Lesbarkeit, bzw. Explizität dessen was man schreibt, nichts ist zuviel oder zu wenig umschrieben.
try
except on E: Exception do if E is EThisException then HandleThisException(E) else if E is EThatException then HandleThatException(E) else HandleAnyException(E); end; 2.) ob man on E: XYZ do abfragt oder E is XYZ ist egal, dahinter wird der Compiler den gleichen Code erzeugen, für die Klassentyp Abfrage. 3.) Programablaufpfad, bei deiner Lösung fragst du unnötigerweise mit wesentlich höherer Wahrscheinlichkeit die Exception Klasse ab. Bei meinem wird auf grund der kaskadierten IF Abfrage die Wahrscheinlichkeit das zb. HandleAnyException() aufgerufen wird drastisch reduziert das die Wahscheinlichkeiten für EThisException und ETahtException davon abzuziehen sind. Mein Vorschlag ist also effizenzter. Gruß Hagen |
Re: ersetzt try..except begin..end?
Es ginge glaub ich aus so
Delphi-Quellcode:
Das hat dann aber eine Klassenabfrage in der letzten Zeile mehr als die IF Abfrage.
try
except on E: EThisException do HandleThisException(E) else on E: EThatException do HandleThatException(E) else on E: Exception do HandleAnyException(E); end; Zudem wird bei jedem on E: XYZ do erneut aus dem SEH Frame das Exception Object geladen werden müssen. Das bedeutet 2 indirekte Specherzugriffe mehr pro dieser Abfrage. Die IF Abfrage Methode holt also nur einmalig E aus dem SEH Frame im Stack. Danach verhalten sich die IF Abfragen wie in einem with E do Block. Aus meiner Sicht also effizienter und auch leichter lesbar. Die Lesbarkeit liegt aber oft im Auge des Betrachters, die entstehdne Funktionalität aber nicht. Und exakt in diesem Punkt unterscheiden sich unsere Lösungen beträchtlich. Gruß Hagen |
Re: ersetzt try..except begin..end?
Wir können das mal herleiten.
Wir wissen das wir uns in einem absolut logischen und abgeschlossenen System bewegen, auf einem Computer und in der Syntax der Sprache Delphi.
Delphi-Quellcode:
was macht dieses,
try
except on E: Exeption do end; on E: Exception do mal ausgedrückt in Delphi, denn eigentlich ?
Delphi-Quellcode:
Nun schreiben wir die Abfrage wie sie Alzaimar benutzt um
try
except with Hole_Exception_Object_Aus_SEH in variable E do if E is Klassentyp then end;
Delphi-Quellcode:
Was wissen wir am Punkt 1.) ?
try
except with Hole_Exception_Object_Aus_SEH in variable E do if E is EThisException then begin HandleThisException(E); end; // 1.) with Hole_Exception_Object_Aus_SEH in variable E do if E is EThatException then begin HandleThatException(E); end; // 2.) with Hole_Exception_Object_Aus_SEH in variable E do if E is Exception then begin HandleAnyException(E); end; end; Wir wissen das falls die vorherige Abfrage zutreffen würde wir die Abfrage in 1.) einsparen könnten. Denn wenn E vom Typ EThisException ist dann kann sie nicht vom Typ EThatException mehr sein. Aber stellen wir uns mal vor EThisException wäre von EThatException abgeleitet ? Dann würde die erste Abfrage zutreffen und die bei 1.) und 2.) aber auch ? Macht es Sinn, bzw. ist es sogar beabsichtigt das man dann zwei bzw. sogar drei Behandlungsroutinen für eine Exception ausführt ? Meistens, ja fast immer, macht sowas keinen Sinn. Wir können also vereinfachen und sogar eventuelle logische Fehler beseitigen.
Delphi-Quellcode:
Wir kaskadieren die IF Anfragen und verkürzen so den Programablaufpfad. Der Code wird dadurch sogar noch schneller ausgeführt.
try
except with Hole_Exception_Object_Aus_SEH in variable E do if E is EThisException then begin HandleThisException(E); end else with Hole_Exception_Object_Aus_SEH in variable E do if E is EThatException then begin HandleThatException(E); end else with Hole_Exception_Object_Aus_SEH in variable E do if E is Exception then begin HandleAnyException(E); end; end; Nun stellen wir fest das die "Funktion" Hole_Exception_Object_Aus_SEH dreimalig aufrufen. Hinter jedem dieser Aufrufe versteckt sich produzierter Code, davon abgesehen ist es auch redundant. Wir vereinfachen
Delphi-Quellcode:
Wir stellen fest das die vielen begin end Blöcke überflüssige Redundanz darstellen. Das alles müssen wir beim Lesen mit den Augen erfassen, im Hirn übersetzen, und das für Nichts. Es ist demzufolge nicht explizit.
try
except with Hole_Exception_Object_Aus_SEH in variable E do if E is EThisException then begin HandleThisException(E); end else if E is EThatException then begin HandleThatException(E); end else if E is Exception then begin HandleAnyException(E); end; end; wir vereinfachen
Delphi-Quellcode:
Wir wissen das alle Exception Klassen von der Basisklasse Exception abgeleitet werden. Also ist die letzte IF Abfrage überflüssig, sie ist immer WAHR.
try
except with Hole_Exception_Object_Aus_SEH in variable E do if E is EThisException then HandleThisException(E) else if E is EThatException then HandleThatException(E) else if E is Exception then HandleAnyException(E); end; wir vereinfachen
Delphi-Quellcode:
Wir haben vorher die on E: Exception do Syntax in eine logische Form gebracht die uns besser erklärt was da vor sich geht. Diesen Abstraktionsschritt machen wir rückgängig.
try
except with Hole_Exception_Object_Aus_SEH in variable E do if E is EThisException then HandleThisException(E) else if E is EThatException then HandleThatException(E) else HandleAnyException(E); end;
Delphi-Quellcode:
Wir resümieren: Das zu lösende Problem wurde in der Delphi Syntax auf ein nicht mehr reduzierbares Maß verkürzt. Jede weitere Reduktion würde die angestebte und sinnvolle Funktionalität verändern.
try
except on E: Exception do if E is EThisException then HandleThisException(E) else if E is EThatException then HandleThatException(E) else HandleAnyException(E); end; Anders ausgedrückt: es ist eben keine Stilfrage wie man was schreibt sondern eine logisch herleitbare und sinnvoll auf ein notweniges Maß reduzierbare Aufgabe des Programmierers. Die Explizität in unseren Sourcezeilen ist also eine logische Notwendigkeit damit wir nur das exakt umschreiben was auch minimal notwendig ist um ein Problem zu lösen. Wer als Programmierer meint er müsste aus modischen Gründen es nicht so handhaben der kann defakto eben nicht programmieren. Gut das sind harte Worte, unfair vielleicht, aber im Grunde absolut richtig. Ein guter Stil zeichnet sich also dadurch aus das er explizit ist. Jede Weigerung es nicht so zu handhaben kann demzufolge nicht mehr auf logischen Gründen basierend untermauert werden. Es sind meistens emotionale Vorlieben, Sturheit, nicht Lernfähigkeit, aus Prinzip oder Gewohnheiten, aber garantiert nicht überlegtes Denken. Es stellt sich die Frage: Was machen den Programmierer den ganzen Tag lang ? Gruß Hagen |
Re: ersetzt try..except begin..end?
Hallo Hagen,
ich habe mir einmal die Mühe gemacht, beide Lösungen mit dem Debugger schrittweise zu durchlaufen. Bei dem von alzaimar vorgeschlagenen Code lande ich (nach dem Fehlerdialog) direkt im Rumpf der passenden on-Anweisung. Im Anschluß an die Fehlerbehandlung erfolgt ein Sprung zum Ende der try-Anweisung, wo das Exception-Objekt über DoneExcept aufgelöst wird. Bei deiner Lösung erfolgt der Sprung zur einzigen on-Anweisung, von dort aus wird über eine Folge von isClass-Aufrufen der passende Handler gesucht. Die Abläufe in Windows (Kernel32 und ntdll) sind bei beiden Lösungen identisch. Sollte deine Lösung dennoch effizienter sein? Mache ich vielleicht einen Denkfehler? Getestet habe ich übrigens mit Delphi 6 - mit und ohne Optimierung. Gruß Hawkeye |
Re: ersetzt try..except begin..end?
Gut jetzt kommt der unangenehme Part für mich.
Zitat:
Tatsächlich ist es so das Delphi im Grunde schon selbstständig alle on E: XYZ do Konstrukte syntaktisch als case of Abfrage umsetzt. Egal wie man es also schreibt es ist vergleichbar mit dem hier
Delphi-Quellcode:
dumerweise wird darauf zumindestens in der Delphi 5 Hilfe nicht explizit hingeweisen, ist aber keine Begründung dafür das ich falsch lag. Nicht destrotrotz verliert meine "Anleitung" dadurch nicht an allgemeiner Gültigkeit. In diesem speziellen Falle bin ich aber tatsächlich auf die syntaktischen Eigentümlichkeiten der Excpetionbehandlung herein gefallen. Man lernt halt doch nie aus ;)
try
except case Exception_Object_Type of EZeroDivide: JandleZeroDivide; EOverflow: HandleOverflow; EMathError: HandleMathError; end; end; Übrigens habe ich es selber auch noch mal getestet und mir den erzeugten Code angeschaut. Hawkeye's du hast also Recht. Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:46 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