Discussion:
VBA: On Error (Resume Next)
(zu alt für eine Antwort)
Martin Brucker
2005-02-23 19:05:04 UTC
Permalink
Hallo zusammen!

Zunächst an dieser Stelle nochmals Danke an Michel, welcher mich auf die
Idee gebracht hat, nur die Verweise meiner Bilder und diese nicht selbst in
der DB zu speichern. (sehr elegante Lösung)
Die Frage, um welche es in diesem Zusammenhang noch geht, ist wie ich es in
VBA programmiere, daß das Program On Error nicht Resume Next "macht", und
mir damit das vorher betrachtete Bild anzeigt, sondern den leeren Rahmen
anzeigt, wenn kein Bild vorhanden ist. (meine VBA Kenntnisse sind leider
äußerst spärlich) --> On Error "ImageFrame 1 und 2 leer" sozusagen.

Private Sub Form_AfterUpdate()
On Error Resume Next
Me![ImageFrame1].Picture = Me![PRIMÄRES REGIME Ordner] & Me![präop ap
Aufnahme]
Me![Dateipfad] = Me![PRIMÄRES REGIME Ordner]
On Error Resume Next
Me![ImageFrame2].Picture = Me![PRIMÄRES REGIME Ordner] & Me![präop seitliche
Aufnahme]
End Sub

Danke für Lösungen und Vorschläge bereits im voraus

Gruß Martin!
Gerald Aichholzer
2005-02-23 19:34:00 UTC
Permalink
Post by Martin Brucker
Zunächst an dieser Stelle nochmals Danke an Michel, welcher mich auf die
Idee gebracht hat, nur die Verweise meiner Bilder und diese nicht selbst in
der DB zu speichern. (sehr elegante Lösung)
Die Frage, um welche es in diesem Zusammenhang noch geht, ist wie ich es in
VBA programmiere, daß das Program On Error nicht Resume Next "macht", und
mir damit das vorher betrachtete Bild anzeigt, sondern den leeren Rahmen
anzeigt, wenn kein Bild vorhanden ist. (meine VBA Kenntnisse sind leider
äußerst spärlich) --> On Error "ImageFrame 1 und 2 leer" sozusagen.
Private Sub Form_AfterUpdate()
On Error Resume Next
Me![ImageFrame1].Picture = Me![PRIMÄRES REGIME Ordner] & Me![präop ap
Aufnahme]
Me![Dateipfad] = Me![PRIMÄRES REGIME Ordner]
On Error Resume Next
Me![ImageFrame2].Picture = Me![PRIMÄRES REGIME Ordner] & Me![präop seitliche
Aufnahme]
End Sub
Hallo Martin,

On Error Resume Next ist IMHO sowieso kein guter Programmierstil,
Besser ist es, das Vorhandensein des Bildes explizit abzufragen
und die entsprechenden Maßnahmen zu treffen, z.B.

If IsNull(Me![Dateipfad]) Then ' Feld ist leer
Me![ImageFrame1].Picture = Null ' falls man so das Bild entfernt
ElseIf Not FileExists(...) Then
Me![ImageFrame1].Picture = Null
Else
Me![ImageFrame1].Picture = ...
End If

Das ist alles Pseudocode und sollte dir nur eine Idee geben. Ins-
besondere

weiß ich nicht, ob man durch Zuweisen von Null das angezeigte
Bild wieder "löscht"

gibt es die Funktion FileExists() nicht (sie muss selbst pro-
grammiert werden


HTH,
Gerald

"
Andi Mayer..
2005-02-23 20:54:32 UTC
Permalink
On Wed, 23 Feb 2005 20:34:00 +0100, Gerald Aichholzer
Post by Gerald Aichholzer
Hallo Martin,
On Error Resume Next ist IMHO sowieso kein guter Programmierstil,
Besser ist es, das Vorhandensein des Bildes explizit abzufragen
und die entsprechenden Maßnahmen zu treffen, z.B.
If IsNull(Me![Dateipfad]) Then ' Feld ist leer
Me![ImageFrame1].Picture = Null ' falls man so das Bild entfernt
ElseIf Not FileExists(...) Then
Me![ImageFrame1].Picture = Null
Else
Me![ImageFrame1].Picture = ...
End If
Das ist alles Pseudocode und sollte dir nur eine Idee geben. Ins-
besondere
weiß ich nicht, ob man durch Zuweisen von Null das angezeigte
Bild wieder "löscht"
gibt es die Funktion FileExists() nicht (sie muss selbst pro-
grammiert werden
ich würde dir trotzdem on error resume next empfehlen

auch wenn Dir(pathName)<>"" wahr ist (das file existiert) kann die
Datei trotzdem beschädigt sein und Access bleibt mit einer
Fehlermeldung stehen:
Z.B 2114: "Microsoft Access unterstützt das Format der Datei
'D:\DIDI\PreisListe\Didi\thumbs\4190906.jpg' nicht, oder die Datei ist
zu groß. Versuchen Sie die Datei in das BMP- oder GIF-Format zu
konvertieren."

diese Datei ist 0 Byte groß gewesen (Übertragungsfehler)

ich löse das so:

on error resume next
Me.Bild0.Picture = pathName

If Me.Bild0.Picture <> PathName Then Me.Bild0.Picture = ""

on error goto 0
--
If you expect an answer to a personal mail, add the word "manfred" to the first 10 lines in the message
MW
Gerald Aichholzer
2005-02-23 21:07:00 UTC
Permalink
Post by Andi Mayer..
On Wed, 23 Feb 2005 20:34:00 +0100, Gerald Aichholzer
Post by Gerald Aichholzer
On Error Resume Next ist IMHO sowieso kein guter Programmierstil,
Besser ist es, das Vorhandensein des Bildes explizit abzufragen
und die entsprechenden Maßnahmen zu treffen, z.B.
ich würde dir trotzdem on error resume next empfehlen
auch wenn Dir(pathName)<>"" wahr ist (das file existiert) kann die
Datei trotzdem beschädigt sein und Access bleibt mit einer
Z.B 2114: "Microsoft Access unterstützt das Format der Datei
'D:\DIDI\PreisListe\Didi\thumbs\4190906.jpg' nicht, oder die Datei ist
zu groß. Versuchen Sie die Datei in das BMP- oder GIF-Format zu
konvertieren."
diese Datei ist 0 Byte groß gewesen (Übertragungsfehler)
Hallo Andi,

in meinem Beispiel habe ich auf den Error-Handler verzichtet,
jedoch vergessen, darauf hinzuweisen.

Im konkreten Fall mag On Error Resume Next "erlaubt" sein
(d.h. kein Bild anzeigen, falls ein Fehler dabei auftritt),
generell bin ich dennoch der Meinung, dass man einen Error-
Handler angeben soll, indem man je nach Fehlernummer ent-
sprechend reagiert.

lg,
Gerald
Andi Mayer..
2005-02-23 23:11:45 UTC
Permalink
On Wed, 23 Feb 2005 22:07:00 +0100, Gerald Aichholzer
Post by Gerald Aichholzer
Hallo Andi,
in meinem Beispiel habe ich auf den Error-Handler verzichtet,
jedoch vergessen, darauf hinzuweisen.
Im konkreten Fall mag On Error Resume Next "erlaubt" sein
(d.h. kein Bild anzeigen, falls ein Fehler dabei auftritt),
generell bin ich dennoch der Meinung, dass man einen Error-
Handler angeben soll, indem man je nach Fehlernummer ent-
sprechend reagiert.
da geb ich dir vollständig recht, aber manchmal gehts halt einfach
nicht.
In diesen Fall kenne ich Fehler 2114 und 2220, weiß aber nicht was
sonst noch anfallen könnte, daher sicherheitshalber alle Fehler
"ignorieren".
--
If you expect an answer to a personal mail, add the word "manfred" to the first 10 lines in the message
MW
Gottfried Lesigang
2005-02-24 00:08:25 UTC
Permalink
Hallo Andi, hallo Gerald!
Post by Andi Mayer..
Post by Gerald Aichholzer
Im konkreten Fall mag On Error Resume Next "erlaubt" sein
(d.h. kein Bild anzeigen, falls ein Fehler dabei auftritt),
generell bin ich dennoch der Meinung, dass man einen Error-
Handler angeben soll, indem man je nach Fehlernummer ent-
sprechend reagiert.
da geb ich dir vollständig recht, aber manchmal gehts halt einfach
nicht.
In diesen Fall kenne ich Fehler 2114 und 2220, weiß aber nicht was
sonst noch anfallen könnte, daher sicherheitshalber alle Fehler
"ignorieren".
Ich gebe dir da nicht vollständig Recht. Weder ist "On Error Resume Next"
schlechter Stil noch ist es generell besser in einem Fehlerhandler die
Fehlernummern abzufragen. Ganz im Gegenteil! Es ist ein sehr probates Mittel
*zusätzlich* zu einem vorhandenen Fehlerhandler bei verdächtigen Zeilen
(Dateizugriffe etc.) *sofort* und an der richtigen Stelle zu reagieren. Oft
genügt es doch schon zu wissen, dass etwas schief gegangen ist - ganz ohne
Fehlernummern! Das geht viel leichter als mit Flags und weiß der Kuckuck im
Fehlerhandler. Natürlich darf man nicht vergessen, dass "On Error Resume
Next" auch wieder abzuschalten...

Das hochgejubelte Konzept in ".NET" mit "try{}" und "catch{}" funktioniert
letztlich doch auch so ähnlich.


Beispiele:

Ich kann mit ...

<Aircode ungetestet="true">

Public Function Contains(Key As String) As Boolean
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy=MyCollection.Item(Key)
Contains=CBool(Err)
End Function

...viel eleganter und rascher prüfen, ob ein Element in einer Collection
enthalten ist, als wenn ich alle Elemente abfrage (An den Key kommst du
dabei gar nicht so leicht heran...)

Oder:

Ich nutze ein TreeView, in dem ich Datensätze nach Jahren sortiert
darstelle.

Dim tmpNodeJahr As Node
On Error Resume Next

... dann in der Schleife über das Recordset

'Ich versuche einfach auf gut Glück den Jahres-Knoten hinzuzufügen
Set tmpNodeJahr = MyTreeView.Nodes.Add Key:="Jahr" & !Jahr, Text:=Jahr
If Err Then
Err.Clear
'Es gibt schon einen Knoten mit diesem Key (z.B. 'Jahr2002')
'Gut, dann referenziere ich eben den vorhandenen!
Set tmpNodeJahr = MyTreeView.Nodes("Jahr" & !Jahr)
End If

'Die eigentliche Datenzeile einfügen
'tmpNodeJahr zeigt nun auf den richtigen Jahresknoten!
MyTreeView.Nodes.Add Relative:=tmpNodeJahr, Relationship:=tvwChild,
Key:="die ZeilenID", Text:="der Dateninhalt"

</Aircode>

Ich für meinen Teil setze "On Error Resume Next" sehr häufig ein.

lg
Gottfried
Gottfried Lesigang
2005-02-24 00:56:46 UTC
Permalink
Es heißt natürlich
Post by Gottfried Lesigang
Public Function Contains(Key As String) As Boolean
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy=MyCollection.Item(Key)
Contains = NOT CBool(Err)
Post by Gottfried Lesigang
End Function
Philipp Stiefel
2005-02-24 07:43:11 UTC
Permalink
Post by Gottfried Lesigang
Ich gebe dir da nicht vollständig Recht. Weder ist "On Error Resume Next"
schlechter Stil noch ist es generell besser in einem Fehlerhandler die
Fehlernummern abzufragen. Ganz im Gegenteil! Es ist ein sehr probates Mittel
*zusätzlich* zu einem vorhandenen Fehlerhandler bei verdächtigen Zeilen
(Dateizugriffe etc.) *sofort* und an der richtigen Stelle zu reagieren. Oft
genügt es doch schon zu wissen, dass etwas schief gegangen ist - ganz ohne
Fehlernummern! Das geht viel leichter als mit Flags und weiß der Kuckuck im
Fehlerhandler. Natürlich darf man nicht vergessen, dass "On Error Resume
Next" auch wieder abzuschalten...
Das von dir beschriebene Vorgehen lässt sich sowohl mit On Error
Resume Next als auch mit On Error Goto XY realisieren. Du kannst
ja für einen bestimmten Block auch einen anderen Error-Handler
verwenden, als für den Rest der Prozedur. - Allerdings ist der
Einsatz von On Error Goto letztendlich auch nur ein Goto und
bringt damit einen gewissen Spaghetti-Effekt mit sich.

IMHO kommt es weniger darauf an, welche der beiden Varianten man
bei der Behandlung von Fehlern verwendet, sondern darauf, dass man
die Fehler nicht einfach unterschlägt und ignoriert, wie es mit
On Error Resume Next gern gemacht wird und dass man keine 'geratene'
Annahme macht, was denn der Fehler war.- Zu Letzterem komme ich
unten bei den Beispielen nochmal.
Post by Gottfried Lesigang
Das hochgejubelte Konzept in ".NET" mit "try{}" und "catch{}" funktioniert
letztlich doch auch so ähnlich.
Ein try/catch-Block hat von der Funktionalität IMHO aber wesentlich
mehr Ähnlichkeit mit einen On Error Goto als mit O.E. Resume Next.
Der wesentliche Unterschied zu den "klassichen" Error-Handlern in
VB(A) liegt darin, dass es sich um einen klar strukturierten Block
handelt und damit dem Spaghetti-Effekt entgegengewirkt wird.
Schön! Daran lässt sich gut verdeutlichen, warum die Auswertung der
Fehlernummer durchaus wichtig ist und man nicht einfach annehmen
sollte zu wissen, was der Fehler ist, ohne es zu prüfen.
Post by Gottfried Lesigang
Ich kann mit ...
<Aircode ungetestet="true">
Public Function Contains(Key As String) As Boolean
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy=MyCollection.Item(Key)
Contains=CBool(Err)
End Function
...viel eleganter und rascher prüfen, ob ein Element in einer Collection
enthalten ist, als wenn ich alle Elemente abfrage (An den Key kommst du
dabei gar nicht so leicht heran...)
Ja, und was passiert hier wenn MyCollection nicht instanziert
wurde? Genau durch sowas entstehen die widerlichsten Bugs
überhaupt, weil die Funktione "fehlerfrei" druchläuft obwohl
das Objekt mit dem sie arbeitet nicht existiert. - Das wäre
IMO einen ganz gewaltigen Fehler wert!

[...]
Post by Gottfried Lesigang
Ich für meinen Teil setze "On Error Resume Next" sehr häufig ein.
Wenn du es so machst, wie in den Beispielen, würde ich das
dringend überdenken!

Gruß
Phil
--
Bitte verwendet für Fragen zu Access mit DBMS-Server-Backends
die Newsgroup microsoft.public.de.access.clientserver! Danke!

Richtig zitieren im Usenet -> http://got.to/quote
Gottfried Lesigang
2005-02-24 21:57:23 UTC
Permalink
Hallo Philipp!
Post by Philipp Stiefel
[Ausführungen pro On Error Resume Next]
IMHO kommt es weniger darauf an, welche der beiden Varianten man
bei der Behandlung von Fehlern verwendet, sondern darauf, dass man
die Fehler nicht einfach unterschlägt und ignoriert, wie es mit
On Error Resume Next gern gemacht wird und dass man keine 'geratene'
Annahme macht, was denn der Fehler war.- Zu Letzterem komme ich
unten bei den Beispielen nochmal.
Das versteht sich von selbst.
Post by Philipp Stiefel
Das hochgejubelte Konzept in ".NET" mit "try{}" und "catch{}"
funktioniert
letztlich doch auch so ähnlich.
Ein try/catch-Block hat von der Funktionalität IMHO aber wesentlich
mehr Ähnlichkeit mit einen On Error Goto als mit O.E. Resume Next.
Das sehe ich nicht so, weil man diese Konstruktion jeweils gezielt für eine
oder einige Zeilen Code verwendet und ggf. mehrfach in einer Prozedur. Man
probiert etwas und reagiert *sofort* auf mögliche Fehler - das ist "On Error
Resume Next". Man schließt ja nicht die *ganze* Sub wahllos in den try-Block
und reagiert dann auf etwaige Fehler - das wäre "On Error Goto
Sprungmarke"...
Post by Philipp Stiefel
Der wesentliche Unterschied zu den "klassichen" Error-Handlern in
VB(A) liegt darin, dass es sich um einen klar strukturierten Block
handelt und damit dem Spaghetti-Effekt entgegengewirkt wird.
Noch wichtiger empfinde ich aber die bewusste lokalisierung rund um
"verdächtige" Codeteile...
Post by Philipp Stiefel
Schön! Daran lässt sich gut verdeutlichen, warum die Auswertung der
Fehlernummer durchaus wichtig ist und man nicht einfach annehmen
sollte zu wissen, was der Fehler ist, ohne es zu prüfen.
Tja, auch das sehe ich ganz anders, auch wenn du natürlich Recht hast, dass
man Fehler nicht einfach erraten und ignorieren sollte... Es gibt aber genug
Situationen, wo ich nur wissen will: Geht das oder geht das nicht?
Post by Philipp Stiefel
Ich kann mit ...
<Aircode ungetestet="true">
Public Function Contains(Key As String) As Boolean
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy=MyCollection.Item(Key)
Contains=CBool(Err)
End Function
...viel eleganter und rascher prüfen, ob ein Element in einer Collection
enthalten ist, als wenn ich alle Elemente abfrage (An den Key kommst du
dabei gar nicht so leicht heran...)
Ja, und was passiert hier wenn MyCollection nicht instanziert
wurde?
Mit dieser Funktion will ich nur prüfen, ob ein gegebener Key in der Liste
entahlten ist. Wenn die Liste "Nothing" ist, dann ist der Key ja nicht
enthalten, das Ergebnis somit richtig. Will ich ein Element konkret abrufen
bzw. hinzufügen, dann müsste natürlich ein entsprechender Fehler geworfen
werden - hier aber nicht! Außerdem weiß ich recht gut, welche Objekte ich wo
und wie instanziere. Ich empfinde den Umgang mit "New" als ebenso relevant
wie den Umgang mit "On Error"!
Post by Philipp Stiefel
Genau durch sowas entstehen die widerlichsten Bugs
So was hatte ich das letzte Mal vor über 1 Jahr (Eine Property lieferte ein
Objekt und ich hatte das "Set" vergessen - Fehlersuche max. 20 min). Konkret
verwende ich obiges in eigenen Listenklassen. Das interne Collection-Objekt
wird in Class_Initialize instanziert und steht dann nie wieder links vom
"=". Da gibt es kein "Nothing"...
Post by Philipp Stiefel
überhaupt, weil die Funktione "fehlerfrei" druchläuft obwohl
das Objekt mit dem sie arbeitet nicht existiert. - Das wäre
IMO einen ganz gewaltigen Fehler wert!
Wie gesagt: Ich finde das an dieser Stelle ganz und gar keinen "gewaltigen
Fehler" wert, da ich doch nur wissen will, ob ein gegebener Key bereits
existiert - und genau das ist ja dann nicht der Fall...
Post by Philipp Stiefel
Ich für meinen Teil setze "On Error Resume Next" sehr häufig ein.
Wenn du es so machst, wie in den Beispielen, würde ich das
dringend überdenken!
Das kommt ein bisschen überheblich rüber...

Beschreibe mir doch mal einen besseren Weg zu prüfen ob ein Key in einer
Collection enthalten ist, ohne "On Error Resume Next" zu verwenden.

lg
Gottfried
Philipp Stiefel
2005-03-02 14:58:15 UTC
Permalink
Sorry, für die Späte Antwort. Ich war die letzten Tage anderweitig
ausgelastet.
Post by Gottfried Lesigang
Post by Philipp Stiefel
[Ausführungen pro On Error Resume Next]
IMHO kommt es weniger darauf an, welche der beiden Varianten
man bei der Behandlung von Fehlern verwendet, sondern darauf,
dass man die Fehler nicht einfach unterschlägt und ignoriert,
wie es mit On Error Resume Next gern gemacht wird und dass man
keine 'geratene' Annahme macht, was denn der Fehler war.- Zu
Letzterem komme ich unten bei den Beispielen nochmal.
Das versteht sich von selbst.
OK, dann sind wir im wichtigsten Punkt schon mal einer Meinung.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Das hochgejubelte Konzept in ".NET" mit "try{}" und "catch{}" funktioniert
letztlich doch auch so ähnlich.
Ein try/catch-Block hat von der Funktionalität IMHO aber
wesentlich mehr Ähnlichkeit mit einen On Error Goto als mit
O.E. Resume Next.
Das sehe ich nicht so, weil man diese Konstruktion jeweils
gezielt für eine oder einige Zeilen Code verwendet und ggf.
mehrfach in einer Prozedur. Man probiert etwas und reagiert
*sofort* auf mögliche Fehler - das ist "On Error Resume Next".
Man schließt ja nicht die *ganze* Sub wahllos in den try-Block
und reagiert dann auf etwaige Fehler - das wäre "On Error Goto
Sprungmarke"...
Bei einem "On Error goto ..." wird auch *sofort* bei Auftreten
des Fehlers in den Errorhandler gesprungen. Diese Unterscheidung
ist daher so nicht richtig. Du musst auch nicht dieselbe "On Error
goto ..." Srpungmarke für die ganze Prozedur verwenden. Vielleicht
mal ein wenig Pseudocode um das zu vedeutlichen.


'-----------------------------------------------------------
Sub Demo
On Error Goto Demo_Err_Allgemein

Call TuIrgendwas()
Call TuWasAnderes(a,b,c)

On Error Goto Demo_Err_Dateizugriff

Open Datei
Lese Datei
Schließe Datei

On Error Goto Demo_Err_Allgemein

Call TuNochwasAnderes()

Exit sub

Demo_Err_Allgemein:
Msgbox "Es ist ein allgemeiner Fehler aufgetreten!"
Exit sub

Demo_Err_Dateizugriff:
If DateiNochGeöffnet Then
Schließe Datei
End If
Msgbox "Es ist ein Fehler beim Dateizugriff aufgetreten!"
Exit sub

End Sub
'-----------------------------------------------------------

Damit bist du, bis auf den unangenehmen Spaghetti-Effekt, da wo
du mit einem Try/Catch-Block auch wärst. Mit einem "On Error
Resume Next" kommst du da aber nicht so einfach hin, weil du
dann nach jeder Anweisung übeprüfen musst (solltest) ob ein
Fehler aufgetreten ist.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Der wesentliche Unterschied zu den "klassichen" Error-Handlern
in VB(A) liegt darin, dass es sich um einen klar strukturierten
Block handelt und damit dem Spaghetti-Effekt entgegengewirkt
wird.
Noch wichtiger empfinde ich aber die bewusste lokalisierung rund
um "verdächtige" Codeteile...
Wie oben demonstriert ist diese Lokalisierung ohne weiteres
möglich, sie ist nur nicht so deutlich strukturiert.


[...]
Post by Gottfried Lesigang
Post by Philipp Stiefel
Public Function Contains(Key As String) As Boolean
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy=MyCollection.Item(Key)
Contains=CBool(Err)
End Function
...viel eleganter und rascher prüfen, ob ein Element in einer
Collection enthalten ist, als wenn ich alle Elemente abfrage
(An den Key kommst du dabei gar nicht so leicht heran...)
Ja, und was passiert hier wenn MyCollection nicht instanziert
wurde?
Mit dieser Funktion will ich nur prüfen, ob ein gegebener Key in
der Liste entahlten ist. Wenn die Liste "Nothing" ist, dann ist
der Key ja nicht enthalten, das Ergebnis somit richtig. Will ich
ein Element konkret abrufen bzw. hinzufügen, dann müsste
natürlich ein entsprechender Fehler geworfen werden - hier aber
nicht! Außerdem weiß ich recht gut, welche Objekte ich wo und
wie instanziere.
[...]

Wenn du alleine arbeitest ist das OK, solange du konsequent
bist und verinnerlicht hast, wie du mit deinem Code umgehen
musst. Wenn du aber im Team arbeitest und andere Entwickler
deinen Code nutzen, dann finde ich diesen Ansatz nicht gut,
weil er eine bestimmte Ausgangssituation voraussetzt, die
durch den Code selbst nicht verifiziert wird.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Genau durch sowas entstehen die widerlichsten Bugs
So was hatte ich das letzte Mal vor über 1 Jahr (Eine Property
lieferte ein Objekt und ich hatte das "Set" vergessen -
Fehlersuche max. 20 min). Konkret verwende ich obiges in eigenen
Listenklassen. Das interne Collection-Objekt wird in
Class_Initialize instanziert und steht dann nie wieder links vom
"=". Da gibt es kein "Nothing"...
Post by Philipp Stiefel
überhaupt, weil die Funktione "fehlerfrei" druchläuft obwohl
das Objekt mit dem sie arbeitet nicht existiert. - Das wäre
IMO einen ganz gewaltigen Fehler wert!
Wie gesagt: Ich finde das an dieser Stelle ganz und gar keinen
"gewaltigen Fehler" wert, da ich doch nur wissen will, ob ein
gegebener Key bereits existiert - und genau das ist ja dann
nicht der Fall...
Nein, aber ich würde eine solche Methode nie auf ein Objekt
anwenden, wenn ich nicht davon ausgehen würde, dass es bereits
existiert. Ohne hier werten zu wollen, welche Erwartung
/angemessen/ ist, sollte die Tatsache an sich schon ausreichen,
um zu verdeutlichen, dass solche unterschiedlichen Erwartungen
problematisch sind, wenn der Ablauf des Codes mehrere
Interpretationen zulässt.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Ich für meinen Teil setze "On Error Resume Next" sehr häufig ein.
Wenn du es so machst, wie in den Beispielen, würde ich das
dringend überdenken!
Das kommt ein bisschen überheblich rüber...
So war es nicht gemeint.
Post by Gottfried Lesigang
Beschreibe mir doch mal einen besseren Weg zu prüfen ob ein Key
in einer Collection enthalten ist, ohne "On Error Resume Next"
zu verwenden.
Mir ging es nicht prizipiell um das On Error resume Next, sondern
darum dass du nicht prüfst welcher Fehler genau aufgetreten ist.

Eine, in diesem Sinne, bessere Variante der obigen Prozedur:
'-------------------------------------------------
Public Function Contains(Key As String) As Boolean

Dim lngErrNo As Long
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy = MyCollection.Item(Key)
lngErrNo = Err.Number

On Error GoTo 0
If lngErrNo <> 5 Then
Err.Raise lngErrNo
End If

Contains = Not CBool(lngErrNo)

End Function
'-------------------------------------------------

Aber selbst das finde ich wegen dem recht allgemein
gehaltenem 5er-Error schon nicht mehr wirklich gut.

Ich wähle üblicherweise immer den Ansatz, Fehler möglichst
zu vermeiden. D.h. ich würde lieber die Items der Collection
durchgehen und püfen ob das gesuchte enthalten ist. - Je
nach Größe der Collection kann sich das natürlich unangenehm
auf die Performance auswirken. - Wenn es einen konkreten
Grund dafür gibt, würde ich ggfls. einen anderen Ansatz
wählen, aber wirklich erst dann.

Gruß
Phil
--
Bitte verwendet für Fragen zu Access mit DBMS-Server-Backends
die Newsgroup microsoft.public.de.access.clientserver! Danke!

Richtig zitieren im Usenet -> http://got.to/quote
Gottfried Lesigang
2005-03-02 19:25:04 UTC
Permalink
Grüß dich Philip!

[]vorgezogen]
Post by Philipp Stiefel
Post by Gottfried Lesigang
Das kommt ein bisschen überheblich rüber...
So war es nicht gemeint.
Wenn also das Klima wieder passt, dann lässt sich ja prächtig
weiterdiskutieren ;-)
Post by Philipp Stiefel
Post by Gottfried Lesigang
[On Error Resume Next ist näher an try-catch]
Bei einem "On Error goto ..." wird auch *sofort* bei Auftreten
des Fehlers in den Errorhandler gesprungen. Diese Unterscheidung
ist daher so nicht richtig. Du musst auch nicht dieselbe "On Error
goto ..." Srpungmarke für die ganze Prozedur verwenden. Vielleicht
mal ein wenig Pseudocode um das zu vedeutlichen.
Ja, das ist schon klar. Aber ganz oft geht ja, anders als in deinem
Beispiel, nach einer verdächtigen Code-Zeile das Programm noch weiter. Dann
musst du aus deinen Error-Blöcken mit einer "Resume" oder "Resume Next"
Anweisung zurückspringen. Und dann gibt es vielleicht auch Code-Teile, die
jedenfalls abgearbeitet werden sollten (in .NET das "finally"). Dann
springst du wahrscheinlich irgendwie an diese Stelle, lässt aber dein "On
Error Goto Spezialmarke" unverändert. Es gilt dann im anderen Block immer
noch die alte Fehler-Routine...

Ich finde es viel logischer und auch richtiger das Programm von oben nach
unten ablaufen zu lassen, verdächtige Codezeilen zu prüfen, darauf sauber zu
reagieren, dann ein "Err.Clear" und weiter geht's...
Post by Philipp Stiefel
Damit bist du, bis auf den unangenehmen Spaghetti-Effekt, da wo
du mit einem Try/Catch-Block auch wärst.
Ja, immer dann, wenn in allen Error-Fällen die Routine verlassen werden
soll - also selten ;-)
Post by Philipp Stiefel
Mit einem "On Error
Resume Next" kommst du da aber nicht so einfach hin, weil du
dann nach jeder Anweisung übeprüfen musst (solltest) ob ein
Fehler aufgetreten ist.
Ich masse mir an bei einer ganzen Reihe von Zeilen anzunehmen, dass da nix
passiert...
Post by Philipp Stiefel
Post by Gottfried Lesigang
Post by Philipp Stiefel
Der wesentliche Unterschied zu den "klassichen" Error-Handlern
in VB(A) liegt darin, dass es sich um einen klar strukturierten
Block handelt und damit dem Spaghetti-Effekt entgegengewirkt
wird.
Noch wichtiger empfinde ich aber die bewusste lokalisierung rund
um "verdächtige" Codeteile...
Wie oben demonstriert ist diese Lokalisierung ohne weiteres
möglich, sie ist nur nicht so deutlich strukturiert.
Wenn du nun hintennach mehrere Error-Blöcke hast und dann womöglich noch
Rücksprünge stimmt das ganz und gar nicht. Es wird dadurch nur alles
ungeheuer aufgebläht. So würde ich nur arbeiten, wenn ich nach Zeilen
bezahlt wäre ;-)
Post by Philipp Stiefel
Post by Gottfried Lesigang
[Gottfrieds "Contains" Beispiel]
Wenn du alleine arbeitest ist das OK, solange du konsequent
bist und verinnerlicht hast, wie du mit deinem Code umgehen
musst.
Wo liegen denn da die Gefahren? Wenn einer der Collection was hinzufügen
will, oder wenn ein Item abgerufen werden soll, dann gibt es ja einen
Fehler, weil das dort Sinn macht...
Post by Philipp Stiefel
Wenn du aber im Team arbeitest und andere Entwickler
deinen Code nutzen, dann finde ich diesen Ansatz nicht gut,
weil er eine bestimmte Ausgangssituation voraussetzt, die
durch den Code selbst nicht verifiziert wird.
Wieso? Wenn ich an der Stelle wissen will, ob die Collection instanziert
ist, dann kann ich das ganz leicht mit "Is Nothing" - allemal leichter als
höchst überflüsiger Weise einen Fehler hinaufzureichen, diesen oben dann
wieder mit einem extra dafür angelegeten Error-Block abzufangen, nur um
nachher zu wissen, dass der Key eben nicht in der Collection ist.
Post by Philipp Stiefel
Nein, aber ich würde eine solche Methode nie auf ein Objekt
anwenden, wenn ich nicht davon ausgehen würde, dass es bereits
existiert.
Warum? Ich verwende die Fehler als "zweite Rückmeldeschiene" und fahre damit
sehr gut.
Post by Philipp Stiefel
Post by Gottfried Lesigang
Beschreibe mir doch mal einen besseren Weg zu prüfen ob ein Key
in einer Collection enthalten ist, ohne "On Error Resume Next"
zu verwenden.
Mir ging es nicht prizipiell um das On Error resume Next, sondern
darum dass du nicht prüfst welcher Fehler genau aufgetreten ist.
Weil's an der Stelle nicht interessiert. Was sollte ich denn auch mit der
Information anfangen. Letztlich wäre dieser konkrete Fehler sicherlich einer
der "nicht behandelten" in deinem Error-Handler...
Post by Philipp Stiefel
'-------------------------------------------------
Public Function Contains(Key As String) As Boolean
Dim lngErrNo As Long
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy = MyCollection.Item(Key)
lngErrNo = Err.Number
On Error GoTo 0
If lngErrNo <> 5 Then
Err.Raise lngErrNo
End If
Contains = Not CBool(lngErrNo)
End Function
'-------------------------------------------------
So viele Zeilen, nur dafür, dass ich mich einen Stock darüber wieder mit
einem Fehler herum schlagen muss? Wenn schon, dann müsstest du noch die
Fehler-Source puffern und den Routinen-Namen der aktuellen Prozedur
dranhängen, eine Message dazu stellen...
Post by Philipp Stiefel
Ich wähle üblicherweise immer den Ansatz, Fehler möglichst
zu vermeiden. D.h. ich würde lieber die Items der Collection
durchgehen und püfen ob das gesuchte enthalten ist. - Je
nach Größe der Collection kann sich das natürlich unangenehm
auf die Performance auswirken.
Wenn du die Items der Collection durchgehen willst, musst du frisch wieder
mit einer nicht instanzierten Collection rechnen - da beißt sich dann die
Katze in den Schwanz. Wenn du jetzt sagst: "Das kann ich ja mit 'Is Nothing'
abfragen.", dann würde ich sagen: "Eben!"

Wie auch immer: Diskutieren macht Spaß!

lg
Gottfried
Philipp Stiefel
2005-03-07 10:40:12 UTC
Permalink
Hallo Gottfried,
Post by Gottfried Lesigang
Post by Philipp Stiefel
Post by Gottfried Lesigang
[On Error Resume Next ist näher an try-catch]
Bei einem "On Error goto ..." wird auch *sofort* bei Auftreten
des Fehlers in den Errorhandler gesprungen. Diese
Unterscheidung ist daher so nicht richtig. Du musst auch nicht
dieselbe "On Error goto ..." Srpungmarke für die ganze Prozedur
verwenden. Vielleicht mal ein wenig Pseudocode um das zu
vedeutlichen.
Ja, das ist schon klar. Aber ganz oft geht ja, anders als in
deinem Beispiel, nach einer verdächtigen Code-Zeile das Programm
noch weiter. Dann musst du aus deinen Error-Blöcken mit einer
"Resume" oder "Resume Next" Anweisung zurückspringen. Und dann
gibt es vielleicht auch Code-Teile, die jedenfalls abgearbeitet
werden sollten (in .NET das "finally"). Dann springst du
wahrscheinlich irgendwie an diese Stelle, lässt aber dein "On
Error Goto Spezialmarke" unverändert. Es gilt dann im anderen
Block immer noch die alte Fehler-Routine...
Letzteres Problem lässt sich durch ein entsprechendes On Error
Goto lösen. Praktisch ist das aus meiner Sicht aber eher weniger
ein Problem, da es i.d.R. wohl keinen Sinn macht eine Prozedur,
die bereits in einen unerwarteten, d.h. nicht vorher abgeprüften
Fehler gelaufen ist, lang weiterlaufen zu lassen. D.h. eigentlich
sollte sich der noch abzuarbeitende Code auf reine Aufräum-
anweisungen beschränken und diese lassen sich gut in einem Exit-
Block unterbringen.

Das funktioniert natürlich nur dann gut, wenn man /Problem-
situationen/, die man vorher schon erwartet, abprüft, ohne dabei
einen Laufzeitfehler auszulösen.
Post by Gottfried Lesigang
Ich finde es viel logischer und auch richtiger das Programm von
oben nach unten ablaufen zu lassen, verdächtige Codezeilen zu
prüfen, darauf sauber zu reagieren, dann ein "Err.Clear" und
weiter geht's...
Logischer ja, ohne Frage. Das Problem ist aber, dass du bei einem
On Error Resume Next entweder sehr viel Code benötigst, der mit der
eigentlichen Logik der Prozedur nichts zu tun hat, um an allen
Stellen alle möglichen Fehler sinnvoll zu behandeln, oder du mehr
oder weniger große Code-Blöcke hast, bei denen du einfach davon
ausgehst, dass schon alles gut geht und in denen evtuelle Fehler
unter den Tisch fallen.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Damit bist du, bis auf den unangenehmen Spaghetti-Effekt, da wo
du mit einem Try/Catch-Block auch wärst.
Ja, immer dann, wenn in allen Error-Fällen die Routine verlassen
werden soll - also selten ;-)
Wenn "verlassen" einen Exit-Block zum Freigeben evtl. belegter
Ressourcen inkludiert, müsste es für mich heißen:
Also (so gut wie) immer!
Post by Gottfried Lesigang
Post by Philipp Stiefel
Mit einem "On Error
Resume Next" kommst du da aber nicht so einfach hin, weil du
dann nach jeder Anweisung übeprüfen musst (solltest) ob ein
Fehler aufgetreten ist.
Ich masse mir an bei einer ganzen Reihe von Zeilen anzunehmen,
dass da nix passiert...
Ich nicht! - Ich habe das lang getan und bin damit oft genug auf
die Schnautze gefallen. Inzwischen bemühe ich mich sämtliche
Annahmen von irgendetwas aus meinem Code zu verbannen. - Natürlich
gelingt das nicht immer.


[...]
Post by Gottfried Lesigang
Post by Philipp Stiefel
Post by Gottfried Lesigang
Noch wichtiger empfinde ich aber die bewusste lokalisierung
rund um "verdächtige" Codeteile...
Wie oben demonstriert ist diese Lokalisierung ohne weiteres
möglich, sie ist nur nicht so deutlich strukturiert.
Wenn du nun hintennach mehrere Error-Blöcke hast und dann
womöglich noch Rücksprünge stimmt das ganz und gar nicht. Es
wird dadurch nur alles ungeheuer aufgebläht. So würde ich nur
arbeiten, wenn ich nach Zeilen bezahlt wäre ;-)
Ja, das stimmt. Wie gesagt, kommt das aber bei mir praktisch
eigenlich nicht vor. Ab einer gewissen Komplexität ist
Errorhandling mit On Error Goto nicht mehr sinnvoll, aber ich bin
der Meinung, dass das praktisch eher von untergeordneter Bendeutung
ist, da es in einem solchen Fall sowieso sinnvoller, weil lesbarer
ist eine große/komplexe Prozedur in mehrere kleine aufzuteilen.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Post by Gottfried Lesigang
[Gottfrieds "Contains" Beispiel]
Wenn du alleine arbeitest ist das OK, solange du konsequent
bist und verinnerlicht hast, wie du mit deinem Code umgehen
musst.
Wo liegen denn da die Gefahren? Wenn einer der Collection was
hinzufügen will, oder wenn ein Item abgerufen werden soll, dann
gibt es ja einen Fehler, weil das dort Sinn macht...
Z.B. darin dass der Code eine zeit- und ressourcenfreesende
Berechnung für das neue Item, das hinzugefügt werden soll, weil es
nocht nicht in der Collections ist, ausführt, nur um später beim
Hinzufügen festzustellen, dass die ganze Collection nicht
exisitiert.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Wenn du aber im Team arbeitest und andere Entwickler
deinen Code nutzen, dann finde ich diesen Ansatz nicht gut,
weil er eine bestimmte Ausgangssituation voraussetzt, die
durch den Code selbst nicht verifiziert wird.
Wieso? Wenn ich an der Stelle wissen will, ob die Collection
instanziert ist, dann kann ich das ganz leicht mit "Is Nothing"
- allemal leichter als höchst überflüsiger Weise einen Fehler
hinaufzureichen, diesen oben dann wieder mit einem extra dafür
angelegeten Error-Block abzufangen, nur um nachher zu wissen,
dass der Key eben nicht in der Collection ist.
Ich glaube unsere Differenz ist vor allem philosophischer Natur.

Genau das würde ich nämlich nicht tun. Entweder ich reche an einer
bestimmten Stelle damit, dass die Collection nicht exisitiert, dann
prüfe ich sie auf Nothing und leitet ggfls. Maßnahmen ein, oder ich
gehe davon aus dass sie existiert, dann _will_ ich einen brutalen
Fehler, der auch nicht gesondert behandelt wird, wenn meine Annahme
an dieser Stelle falsch war. Ein solcher Fehler in dieser Situation
führt dann zum Abbruch alles laufenden Codes, daher muss dann
ausser Aufräumen
Post by Gottfried Lesigang
Post by Philipp Stiefel
Nein, aber ich würde eine solche Methode nie auf ein Objekt
anwenden, wenn ich nicht davon ausgehen würde, dass es bereits
existiert.
Warum?
Gewohnheit, Philosophie, mein Verständins von einem sauberen
Programmierstil nenn es wie du willst. ;-)
Post by Gottfried Lesigang
Ich verwende die Fehler als "zweite Rückmeldeschiene" und
fahre damit sehr gut.
Ich verstehe nicht so recht, was du mit "zweite Rückmeldeschiene"
meinst. Wie dem auch sei, rein technisch ist gegen deinen Ansatz
nichts einzuwenden, IMO ist er nur nicht "intuitiv", wenn man damit
nicht vertraut ist.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Post by Gottfried Lesigang
Beschreibe mir doch mal einen besseren Weg zu prüfen ob ein
Key in einer Collection enthalten ist, ohne "On Error Resume
Next" zu verwenden.
Mir ging es nicht prizipiell um das On Error resume Next,
sondern darum dass du nicht prüfst welcher Fehler genau
aufgetreten ist.
Weil's an der Stelle nicht interessiert.
Das ist der "philosophische" Unterschied. - Mich interessiert es!
Post by Gottfried Lesigang
Was sollte ich denn
auch mit der Information anfangen. Letztlich wäre dieser
konkrete Fehler sicherlich einer der "nicht behandelten" in
deinem Error-Handler...
Ja, natürlich. Mehr als 95% aller Fehler gehören dazu. Bei Fehlern
die nicht dazu gehören, versuche ich vorher zu prüfen ob sie
auftreten werden und verhindere es dann.
Post by Gottfried Lesigang
Post by Philipp Stiefel
'-------------------------------------------------
Public Function Contains(Key As String) As Boolean
Dim lngErrNo As Long
Dim tmpDummy As Object
On Error Resume Next
Set tmpDummy = MyCollection.Item(Key)
lngErrNo = Err.Number
On Error GoTo 0
If lngErrNo <> 5 Then
Err.Raise lngErrNo
End If
Contains = Not CBool(lngErrNo)
End Function
'-------------------------------------------------
So viele Zeilen, nur dafür, dass ich mich einen Stock darüber
wieder mit einem Fehler herum schlagen muss?
Ja, die Meldung der Fehler gehört idealerweise in das GUI-Layer.
Post by Gottfried Lesigang
Wenn schon, dann
müsstest du noch die Fehler-Source puffern und den
Routinen-Namen der aktuellen Prozedur dranhängen, eine Message
dazu stellen...
Ja, klar. Das war eine vereinfachte Darstellung, in echtem Code tue
ich das natürlich.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Ich wähle üblicherweise immer den Ansatz, Fehler möglichst
zu vermeiden. D.h. ich würde lieber die Items der Collection
durchgehen und püfen ob das gesuchte enthalten ist. - Je
nach Größe der Collection kann sich das natürlich unangenehm
auf die Performance auswirken.
Wenn du die Items der Collection durchgehen willst, musst du
frisch wieder mit einer nicht instanzierten Collection rechnen -
da beißt sich dann die Katze in den Schwanz. Wenn du jetzt
sagst: "Das kann ich ja mit 'Is Nothing' abfragen.", dann würde
ich sagen: "Eben!"
Nein, eben nicht. Dieser Fehler wäre für mich einfach eine nicht
vorgesehene Situation und muss nicht dezidiert behandelt werden.
Post by Gottfried Lesigang
Wie auch immer: Diskutieren macht Spaß!
Es verschafft vor allem interessante Einblicke in die
Programmierstile anderer Entwickler. Selbst wenn man dabei nicht
"zu einem Besseren bekehrt" wird, Lernt man doch welche
Alternativen es gibt, und warum genau man seine eigene Variante
vorzieht.

Viele Grüße
Phil
--
Bitte verwendet für Fragen zu Access mit DBMS-Server-Backends
die Newsgroup microsoft.public.de.access.clientserver! Danke!

Richtig zitieren im Usenet -> http://got.to/quote
Gottfried Lesigang
2005-03-07 18:52:48 UTC
Permalink
Grüß dich Phil!
Post by Philipp Stiefel
[Rücksprüge in den Code nach einem Error]
Letzteres Problem lässt sich durch ein entsprechendes On Error
Goto lösen. Praktisch ist das aus meiner Sicht aber eher weniger
ein Problem, da es i.d.R. wohl keinen Sinn macht eine Prozedur,
die bereits in einen unerwarteten, d.h. nicht vorher abgeprüften
Fehler gelaufen ist, lang weiterlaufen zu lassen. D.h. eigentlich
sollte sich der noch abzuarbeitende Code auf reine Aufräum-
anweisungen beschränken und diese lassen sich gut in einem Exit-
Block unterbringen.
So weit sind wir ja gar nicht auseinander! Ich verwende die
Sprungmarken-Handler natürlich auch. Mir ging es nur um dein allzu
pauschales "OERN ist igitt!" ;-)

Ich habe am Anfang einer Prozedur auch das klassische "On Error Goto
Sprungmarke" und *zusätzlich* häufig "OERN" an "verdächtigen" Stellen.
Natürlich schalte ich danach immer wieder zurück. Dafür mache ich der
besseren Übersicht wegen sogar eine Einrückung...

Es gibt viele Situationen, wo ich per "OERN" einfach eleganter und schneller
ans Ziel komme. Allen voran die "Bist du enthalten"-Frage. Z.B. greife ich
einfach auf eine Userdefined Property zu. Wenn es sie schon gibt: Fein! Kein
Fehler! Weiter geht's. Wenn nicht: Fehler! Macht nichts! Property mit
"CreateProperty" und "Add" hinzuzfügen und Zugriff wiederholen. Und danach
zurück zum "normalen" Fehlerhandling...
Post by Philipp Stiefel
Das funktioniert natürlich nur dann gut, wenn man /Problem-
situationen/, die man vorher schon erwartet, abprüft, ohne dabei
einen Laufzeitfehler auszulösen.
Dafür müsste ich die ganze Collection durchklappern, was bei einem Zugriff
per Key wesentlich optimierter *nocheinmal* erledigt werden wird!
Post by Philipp Stiefel
Ich finde es viel logischer und auch richtiger das Programm von
oben nach unten ablaufen zu lassen, verdächtige Codezeilen zu
prüfen, darauf sauber zu reagieren, dann ein "Err.Clear" und
weiter geht's...
Logischer ja, ohne Frage. Das Problem ist aber, dass du bei einem
On Error Resume Next entweder sehr viel Code benötigst, der mit der
eigentlichen Logik der Prozedur nichts zu tun hat, um an allen
Stellen alle möglichen Fehler sinnvoll zu behandeln, oder du mehr
oder weniger große Code-Blöcke hast, bei denen du einfach davon
ausgehst, dass schon alles gut geht und in denen evtuelle Fehler
unter den Tisch fallen.
Nein, denn da habe ich ja das "normale" Fehlerhandling längst schon wieder
an! Da ich aber aus der Erfahrung nun ganz gut weiß, wo die Probleme lauern,
habe ich höchst selten "unerwartete" Fehler.
Post by Philipp Stiefel
Ja, das stimmt. Wie gesagt, kommt das aber bei mir praktisch
eigenlich nicht vor. Ab einer gewissen Komplexität ist
Errorhandling mit On Error Goto nicht mehr sinnvoll,
Nein? Wie machst du als OERN-Hasser ;-) das denn dann?
Post by Philipp Stiefel
aber ich bin
der Meinung, dass das praktisch eher von untergeordneter Bendeutung
ist, da es in einem solchen Fall sowieso sinnvoller, weil lesbarer
ist eine große/komplexe Prozedur in mehrere kleine aufzuteilen.
ACK
Post by Philipp Stiefel
Post by Philipp Stiefel
Post by Gottfried Lesigang
[Gottfrieds "Contains" Beispiel]
Wenn du alleine arbeitest ist das OK, solange du konsequent
bist und verinnerlicht hast, wie du mit deinem Code umgehen
musst.
Wo liegen denn da die Gefahren? Wenn einer der Collection was
hinzufügen will, oder wenn ein Item abgerufen werden soll, dann
gibt es ja einen Fehler, weil das dort Sinn macht...
Z.B. darin dass der Code eine zeit- und ressourcenfreesende
Berechnung für das neue Item, das hinzugefügt werden soll, weil es
nocht nicht in der Collections ist, ausführt, nur um später beim
Hinzufügen festzustellen, dass die ganze Collection nicht
exisitiert.
Das empfinde ich als recht weit hergeholt. Die ständige und immer
wiederkehrende Ressourcenverschwendung durchs doppelte Abklappern bzw.
durchs Hochreichen unnötiger Fehler macht sicher mehr Probleme.
Post by Philipp Stiefel
Post by Philipp Stiefel
Wenn du aber im Team arbeitest und andere Entwickler
deinen Code nutzen, dann finde ich diesen Ansatz nicht gut,
weil er eine bestimmte Ausgangssituation voraussetzt, die
durch den Code selbst nicht verifiziert wird.
Wieso? Wenn ich an der Stelle wissen will, ob die Collection
instanziert ist, dann kann ich das ganz leicht mit "Is Nothing"
- allemal leichter als höchst überflüsiger Weise einen Fehler
hinaufzureichen, diesen oben dann wieder mit einem extra dafür
angelegeten Error-Block abzufangen, nur um nachher zu wissen,
dass der Key eben nicht in der Collection ist.
Ich glaube unsere Differenz ist vor allem philosophischer Natur.
Genau das würde ich nämlich nicht tun. Entweder ich reche an einer
bestimmten Stelle damit, dass die Collection nicht exisitiert, dann
prüfe ich sie auf Nothing und leitet ggfls. Maßnahmen ein, oder ich
gehe davon aus dass sie existiert, dann _will_ ich einen brutalen
Fehler, der auch nicht gesondert behandelt wird, wenn meine Annahme
an dieser Stelle falsch war. Ein solcher Fehler in dieser Situation
führt dann zum Abbruch alles laufenden Codes, daher muss dann
ausser Aufräumen
Und wenn es an dieser Stelle genügt hätte zu schreiben:

If Err Then
Err.Clear
Set MyCollection = New Collection
Resume
End If

... war es dann wirklich sinnvoll, allen aufrufenden Code mit dem ganzen
Rattenschwanz halbfertiger Prozesse abzubrechen, womöglich durch mehrere
Aufrufhierarchien? Wenn ich ein Problem vor Ort beheben *kann*, dann mache
ich das auch! Typisches Beispiel dafür ist die wohl bekannte "Es befindet
sich keine Diskette im Laufwert A:"-Fehlerschleife...
Post by Philipp Stiefel
Post by Philipp Stiefel
Mir ging es nicht prizipiell um das On Error resume Next,
sondern darum dass du nicht prüfst welcher Fehler genau
aufgetreten ist.
Weil's an der Stelle nicht interessiert.
Das ist der "philosophische" Unterschied. - Mich interessiert es!
Du wirst dein Programm doch hoffentlich nicht an dieser Stelle 30
Millisekunden über den Fehler meditieren lassen ;-)
Post by Philipp Stiefel
Post by Philipp Stiefel
[Phils "Contains"-Vorschlage]
So viele Zeilen, nur dafür, dass ich mich einen Stock darüber
wieder mit einem Fehler herum schlagen muss?
Ja, die Meldung der Fehler gehört idealerweise in das GUI-Layer.
Also reiche ich diesen Fehler, der mit wenigen Zeilen an Ort und Stelle
behoben wäre, einige Stockwerte hinauf und breche mit einer kryptischen "Das
Speichern ist leider gescheitert!"-Meldung ab? Dem User wird's doch lieber
sein, wenn sein Speicherwunsch durch die *Behebung* des Fehlers gelingt -
jedenfalls mehr als er sich über eine noch so toll formatierte Fehlermeldung
freut ;-)
Post by Philipp Stiefel
Wenn schon, dann
müsstest du noch die Fehler-Source puffern und den
Routinen-Namen der aktuellen Prozedur dranhängen, eine Message
dazu stellen...
Ja, klar. Das war eine vereinfachte Darstellung, in echtem Code tue
ich das natürlich.
Oh Gott! Noch mehr Zeilen! Dafür verwende ich übrigens eine global
instanzierte Fehlerklasse - aber das machst du ja wahrscheinlich auch...
Post by Philipp Stiefel
Wie auch immer: Diskutieren macht Spaß!
Es verschafft vor allem interessante Einblicke in die
Programmierstile anderer Entwickler. Selbst wenn man dabei nicht
"zu einem Besseren bekehrt" wird, Lernt man doch welche
Alternativen es gibt, und warum genau man seine eigene Variante
vorzieht.
Also bitteschön: Philosophieren macht Spaß!

lg
Gottfried
Philipp Stiefel
2005-03-08 08:55:05 UTC
Permalink
Hallo Gottfried,
Post by Gottfried Lesigang
Post by Philipp Stiefel
[Rücksprüge in den Code nach einem Error]
Letzteres Problem lässt sich durch ein entsprechendes On Error
Goto lösen. Praktisch ist das aus meiner Sicht aber eher
weniger ein Problem, da es i.d.R. wohl keinen Sinn macht eine
Prozedur, die bereits in einen unerwarteten, d.h. nicht vorher
abgeprüften Fehler gelaufen ist, lang weiterlaufen zu lassen.
D.h. eigentlich sollte sich der noch abzuarbeitende Code auf
reine Aufräum- anweisungen beschränken und diese lassen sich
gut in einem Exit- Block unterbringen.
So weit sind wir ja gar nicht auseinander! Ich verwende die
Sprungmarken-Handler natürlich auch. Mir ging es nur um dein
allzu pauschales "OERN ist igitt!" ;-)
Moment! Dass habe ich so pauschal nicht geschrieben. Ich sage
nur OERN verleitet dazu, Fehler zu verschlucken bzw. alle
Fehler pauschal über einen Kamm zu scheeren. Diese häufigen
"Nebenwirkungen" sind igitt, nicht das OERN selbst.
Post by Gottfried Lesigang
Ich habe am Anfang einer Prozedur auch das klassische "On Error
Goto Sprungmarke" und *zusätzlich* häufig "OERN" an
"verdächtigen" Stellen. Natürlich schalte ich danach immer
wieder zurück. Dafür mache ich der besseren Übersicht wegen
sogar eine Einrückung...
Da sind wir uns dann doch schon weitgehend einig!
Post by Gottfried Lesigang
Es gibt viele Situationen, wo ich per "OERN" einfach eleganter
und schneller ans Ziel komme. Allen voran die "Bist du
enthalten"-Frage. Z.B. greife ich einfach auf eine Userdefined
Property zu. Wenn es sie schon gibt: Fein! Kein Fehler! Weiter
geht's. Wenn nicht: Fehler! Macht nichts! Property mit
"CreateProperty" und "Add" hinzuzfügen und Zugriff wiederholen.
Und danach zurück zum "normalen" Fehlerhandling...
Auch das ist absolut legitim. Nur bei der Umsetzung (d.h. deinen
Beispielen) scheinen IMO ein wenig die o.g. Nebenwirkungen des OERN
aufzutreten, die mich dazu bringen, dem OERN zwar nicht grundsätzlich
ablehnend, aber doch recht kritisch gegenüberzustehen,
Post by Gottfried Lesigang
Post by Philipp Stiefel
Das funktioniert natürlich nur dann gut, wenn man /Problem-
situationen/, die man vorher schon erwartet, abprüft, ohne
dabei einen Laufzeitfehler auszulösen.
Dafür müsste ich die ganze Collection durchklappern, was bei
einem Zugriff per Key wesentlich optimierter *nocheinmal*
erledigt werden wird!
Nicht unbedingt. Eine Prüfung der Collection auf Nothing und ein
entsprechender Fehler, der separat behandelt, bzw. nach oben
durchgereicht wird, würden meinen Ansprüchen eigentlich schon genüge
tun. Eine weitere, bessere Alternative wäre auch die Prüfung der
Fehlernummer. Damit hättest du die Punkte, die ich bei der
_Umsetzung_ des OERN beanstande, bereits ausgeräumt.


[...]
Post by Gottfried Lesigang
Post by Philipp Stiefel
Das Problem ist aber, dass du bei
einem On Error Resume Next entweder sehr viel Code benötigst,
der mit der eigentlichen Logik der Prozedur nichts zu tun hat,
um an allen Stellen alle möglichen Fehler sinnvoll zu
behandeln, oder du mehr oder weniger große Code-Blöcke hast,
bei denen du einfach davon ausgehst, dass schon alles gut geht
und in denen evtuelle Fehler unter den Tisch fallen.
Nein, denn da habe ich ja das "normale" Fehlerhandling längst
schon wieder an!
Wenn du das ansonsten so handhabst, gut! In deinen Beispielen waren
aber genau die o.g. Code-Blöcke sichtbar.
Post by Gottfried Lesigang
Da ich aber aus der Erfahrung nun ganz gut
weiß, wo die Probleme lauern, habe ich höchst selten
"unerwartete" Fehler.
Dito. - Aber ich glaube wir gehen da von etwas unterschiedlichen
Standpunkten aus. Die "unerwarteten" Fehler machen aus meiner Sicht
(und bei meinem Programmierstil) 99% aller tatsächlich auftretenden
Fehler aus. Und sie sind es auch um die man sich besonders kümmern
muss, denn die "erwarteten" Fehler sind ja schon speziell behandelt
und sollten damit kein Problem mehr darstellen.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Ja, das stimmt. Wie gesagt, kommt das aber bei mir praktisch
eigenlich nicht vor. Ab einer gewissen Komplexität ist
Errorhandling mit On Error Goto nicht mehr sinnvoll,
Nein? Wie machst du als OERN-Hasser ;-) das denn dann?
Wie oben bereits gesagt, der pauschale OERN-Hasser bin ich nicht. Wie
ich es i.d.R. mache steht im folgenden Absatz.
Post by Gottfried Lesigang
Post by Philipp Stiefel
aber ich bin
der Meinung, dass das praktisch eher von untergeordneter
Bendeutung ist, da es in einem solchen Fall sowieso sinnvoller,
weil lesbarer ist eine große/komplexe Prozedur in mehrere
kleine aufzuteilen.
[...]
Post by Gottfried Lesigang
Post by Philipp Stiefel
Entweder ich reche an
einer bestimmten Stelle damit, dass die Collection nicht
exisitiert, dann prüfe ich sie auf Nothing und leitet ggfls.
Maßnahmen ein, oder ich gehe davon aus dass sie existiert, dann
_will_ ich einen brutalen Fehler, der auch nicht gesondert
behandelt wird, wenn meine Annahme an dieser Stelle falsch war.
Ein solcher Fehler in dieser Situation führt dann zum Abbruch
alles laufenden Codes, daher muss dann ausser Aufräumen
If Err Then
Err.Clear
Set MyCollection = New Collection
Resume
End If
... war es dann wirklich sinnvoll, allen aufrufenden Code mit
dem ganzen Rattenschwanz halbfertiger Prozesse abzubrechen,
womöglich durch mehrere Aufrufhierarchien? Wenn ich ein Problem
vor Ort beheben *kann*, dann mache ich das auch!
Wenn das tatsächlich genügen würde, ja. - Aber ich finde den
Ansatz "Ich arbeite mit einem Objekt und wenn es plötzlich in
irgendeiner tief verborgenen Unterroutine nicht instanziert ist,
erstelle ich dort schnell ein Neues." nicht besonders gut les- und
nachvollziehbar. Es sollte IMO nur einen (oder ganz wenige) Stellen
in einem Ablauf geben, in dem Objekte erzeugt und ggfls.
initialisiert werden.
Post by Gottfried Lesigang
Typisches
Beispiel dafür ist die wohl bekannte "Es befindet sich keine
Diskette im Laufwert A:"-Fehlerschleife...
Finde ich nicht. Das wäre mit das erste, was ich prüfen würde, wenn
der User eine Aktion ausführen will, die auf das Floppy zugreift. -
Bevor da keine Disk drin ist, geht die eigentliche Arbeit gar nicht
erst los.



[...]
Post by Gottfried Lesigang
Du wirst dein Programm doch hoffentlich nicht an dieser Stelle
30 Millisekunden über den Fehler meditieren lassen ;-)
Wenn es dabei hilft, das Programm zu einer tieferen Einsicht gelangen
zu lassen, jederzeit. ;-)
Post by Gottfried Lesigang
Post by Philipp Stiefel
Post by Philipp Stiefel
[Phils "Contains"-Vorschlage]
So viele Zeilen, nur dafür, dass ich mich einen Stock darüber
wieder mit einem Fehler herum schlagen muss?
Ja, die Meldung der Fehler gehört idealerweise in das
GUI-Layer.
Also reiche ich diesen Fehler, der mit wenigen Zeilen an Ort und
Stelle behoben wäre, einige Stockwerte hinauf und breche mit
einer kryptischen "Das Speichern ist leider
gescheitert!"-Meldung ab? Dem User wird's doch lieber sein, wenn
sein Speicherwunsch durch die *Behebung* des Fehlers gelingt -
jedenfalls mehr als er sich über eine noch so toll formatierte
Fehlermeldung freut ;-)
Jein.
- Ja, wenn erforderlich, reiche ich den Fehler bis an den
ursprünglichen Aufrufer hinauf.
- Nein, die Fehlermeldung sollte spezifischer sein. Zumindest
insoweit, dass sie dem Entwickler hilft den Fehler zu finden
und zu beheben.

Der wesentliche Unterschied in meinem Ansatz ist: Wenn ich so sicher
bin den Fehler genau zu erkennen und zu wissen glaube, wie er behoben
werden kann, dann prüfe und behebe ich das _vorher_ ohne einen
Laufzeitfehler auszulösen.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Wenn schon, dann
müsstest du noch die Fehler-Source puffern und den
Routinen-Namen der aktuellen Prozedur dranhängen, eine Message
dazu stellen...
Ja, klar. Das war eine vereinfachte Darstellung, in echtem Code
tue ich das natürlich.
Oh Gott! Noch mehr Zeilen! Dafür verwende ich übrigens eine
global instanzierte Fehlerklasse - aber das machst du ja
wahrscheinlich auch...
Jein, die global instanzierte Fehlerklasse hast du mit dem Err-Objekt
ja bereits. Wenn das nicht ausreicht, verwende ich lieber eine lokale
Kopie davon, die ich an die entsprechenden Handler weiterreiche. -
Ich gebe aber zu, dass ich mit diesem Ansatz noch nicht so endgültig
zufrieden bin.

Viele Grüße
Phil
--
Bitte verwendet für Fragen zu Access mit DBMS-Server-Backends
die Newsgroup microsoft.public.de.access.clientserver! Danke!

Richtig zitieren im Usenet -> http://got.to/quote
Gottfried Lesigang
2005-03-09 00:31:13 UTC
Permalink
Hallo Phil!

[Viel gesnippt]
Post by Philipp Stiefel
Aber ich finde den
Ansatz "Ich arbeite mit einem Objekt und wenn es plötzlich in
irgendeiner tief verborgenen Unterroutine nicht instanziert ist,
erstelle ich dort schnell ein Neues." nicht besonders gut les- und
nachvollziehbar. Es sollte IMO nur einen (oder ganz wenige) Stellen
in einem Ablauf geben, in dem Objekte erzeugt und ggfls.
initialisiert werden.
Jaja, die ganze Unterhaltung ist recht akademisch. Im Endeffekt finden wir
die gleichen Dinge wichtig. Ich programmiere natürlich auch
"fehlervermeidend" ;-)
Post by Philipp Stiefel
Post by Gottfried Lesigang
Typisches
Beispiel dafür ist die wohl bekannte "Es befindet sich keine
Diskette im Laufwert A:"-Fehlerschleife...
Finde ich nicht. Das wäre mit das erste, was ich prüfen würde, wenn
der User eine Aktion ausführen will, die auf das Floppy zugreift. -
Bevor da keine Disk drin ist, geht die eigentliche Arbeit gar nicht
erst los.
Man kann halt nicht an alles denken,,,
Post by Philipp Stiefel
Post by Gottfried Lesigang
Du wirst dein Programm doch hoffentlich nicht an dieser Stelle
30 Millisekunden über den Fehler meditieren lassen ;-)
Wenn es dabei hilft, das Programm zu einer tieferen Einsicht gelangen
zu lassen, jederzeit. ;-)
Viel Glück!
Post by Philipp Stiefel
Der wesentliche Unterschied in meinem Ansatz ist: Wenn ich so sicher
bin den Fehler genau zu erkennen und zu wissen glaube, wie er behoben
werden kann, dann prüfe und behebe ich das _vorher_ ohne einen
Laufzeitfehler auszulösen.
Und wenn du den selben Code einmal an anderer Stelle einsetzt, weißt du
dann, was du alles im Vorfeld checken musst?
Post by Philipp Stiefel
Post by Gottfried Lesigang
[Vorgansweise beim "Hinaufreichen"]
Oh Gott! Noch mehr Zeilen! Dafür verwende ich übrigens eine
global instanzierte Fehlerklasse - aber das machst du ja
wahrscheinlich auch...
Jein, die global instanzierte Fehlerklasse hast du mit dem Err-Objekt
ja bereits. Wenn das nicht ausreicht, verwende ich lieber eine lokale
Kopie davon, die ich an die entsprechenden Handler weiterreiche. -
Ich gebe aber zu, dass ich mit diesem Ansatz noch nicht so endgültig
zufrieden bin.
Meine Klasse kann Log-Einträge machen, verkettet die Source-Info von Aufruf
zu Aufruf, kann selber den Fehler erneut werfen oder eine formatierte
Messagebox ausgeben... Ich könnterte mir - wenn ich das wöllterte - bei
jedem Fehler eine eMail schicken ;-) Der größte Vorteil ist aber bloß eine
einzige Zeile Code im Error-Handler. Nix puffern, einfach "Err" und
Prozedurname (inkl. Modulname) übergeben...

Ich denke, dass wir dieses Thema ausgereizt haben. Von mir aus EOT und danke
für den Gedankenaustausch!

lg
Gottfried
Philipp Stiefel
2005-03-10 10:10:07 UTC
Permalink
Hallo Gottfried,
Post by Gottfried Lesigang
[Viel gesnippt]
[... ebenso...]
Post by Gottfried Lesigang
Post by Philipp Stiefel
Der wesentliche Unterschied in meinem Ansatz ist: Wenn ich so
sicher bin den Fehler genau zu erkennen und zu wissen glaube,
wie er behoben werden kann, dann prüfe und behebe ich das
_vorher_ ohne einen Laufzeitfehler auszulösen.
Und wenn du den selben Code einmal an anderer Stelle einsetzt,
weißt du dann, was du alles im Vorfeld checken musst?
Nein, vermutlich nicht. Genau da sehe ich aber den Vorteil, wenn
die "Erwartungen" des Codes bei Nichterfüllung entweder an der
Stelle einen "harten" Fehler auslösen oder, sofern möglich,
korrigiert werden können.
Post by Gottfried Lesigang
Post by Philipp Stiefel
Post by Gottfried Lesigang
[Vorgansweise beim "Hinaufreichen"]
Oh Gott! Noch mehr Zeilen! Dafür verwende ich übrigens eine
global instanzierte Fehlerklasse - aber das machst du ja
wahrscheinlich auch...
Jein, die global instanzierte Fehlerklasse hast du mit dem
Err-Objekt ja bereits. Wenn das nicht ausreicht, verwende ich
lieber eine lokale Kopie davon, die ich an die entsprechenden
Handler weiterreiche. - Ich gebe aber zu, dass ich mit diesem
Ansatz noch nicht so endgültig zufrieden bin.
Meine Klasse kann Log-Einträge machen, verkettet die Source-Info
von Aufruf zu Aufruf, kann selber den Fehler erneut werfen oder
eine formatierte Messagebox ausgeben... Ich könnterte mir - wenn
ich das wöllterte - bei jedem Fehler eine eMail schicken ;-) Der
größte Vorteil ist aber bloß eine einzige Zeile Code im
Error-Handler.
Joo, Ähnliches habe ich auch schon angefangen, aber ist aber IMO
bei mir noch nicht endgültig ausgereift, weil noch zu unflexibel.
Post by Gottfried Lesigang
Nix puffern, einfach "Err" und Prozedurname
(inkl. Modulname) übergeben...
Puffern ist nur ein Sonderfall, wenn ein Fehler erstmal an Ort und
Stelle behandelt werden und dann erneut ausgelöst werden soll.
Post by Gottfried Lesigang
Ich denke, dass wir dieses Thema ausgereizt haben. Von mir aus
EOT und danke für den Gedankenaustausch!
Sehe ich genauso. Auch an dich vielen Dank für den
Gedankenaustausch.

Viele Grpße
Phil
--
Bitte verwendet für Fragen zu Access mit DBMS-Server-Backends
die Newsgroup microsoft.public.de.access.clientserver! Danke!

Richtig zitieren im Usenet -> http://got.to/quote
Loading...