Tag,
ich möchte ein Programm seine Konfigurations.xml einlesen lassen. Ist
diese Datei nicht vorhanden, gehe ich von einer Neuinstallation aus, und
es soll das Konfigurationsfenster geöffnet werden.
Ich fange dies mit einer try-catch Anweisung ab:
1
/// <summary>
2
/// Lädt im aktuellen Programmpfad die Datei "settings.xml" in das Konfiguration-Objekt
MessageBox.Show("Konfigurationsdatei wurde nicht gefunden. Der Konfigurationsdialog wird geöffnet",
17
"Konfiguration nicht gefunden",MessageBoxButtons.OK,MessageBoxIcon.Exclamation);
18
fileStream.Close();
19
//Konfigurationsdialog öffnen
20
ShowSettingsDialog();
21
//und nochmal versuchen die Datei einzulesen
22
loadSettings();
23
}
24
}
Nun habe ich das Problem, dass mir der Kompiler zu dem Befehl
"fileStream.Close();" sagt, ich verwende hier eine nicht zugewiesene
lokale Variable.
Was ist den hier los? Wie kann ich das Umgehen?
Matthias S. schrieb:> Was ist den hier los? Wie kann ich das Umgehen?
wenn die Datei nicht geöffnet werden kann, dann musst du sie auch nicht
schließen!
Wenn es noch etas komplexer wird kann man
if ( fileStream is not null )
fileStream.Close();
schreiben
Oder was viel besser ist:
using
http://msdn.microsoft.com/de-de/library/yh598w02(v=vs.80).aspx
Moin,
ist irgendwie auch klar: der fileStream ist ja in diesem Fall auch nicht
instantiiert, da du im Catch-Block gelandet bist, also ist das Schließen
desselben auch nicht notwendig.
Problematisch werden könnte es, wenns beim Deserialize knallt, der
filsStream aber angelegt wurde. Deswegen würde ich im try-Block auch nur
den fileStream versuchen zu öffnen, dann ist der definitiv nicht
vorhanden, falls du im catch landest.
Ah,.. ok.
Klarer Denkfehler.
Ich hätte gedacht, ich müsste den FilStream natürlich schließen, bevor
der Catch-Block über den Umweg mit dem SettingsDialog die XML-Datei
schreibt.
Denn:
ich habe da anscheinend noch irgendwo anders einen Denkfehler drinnen.
Wenn ich den über den Catch-Block erscheinenden Dialog ordnungsgemäß
schließe, wird zwar die Datei angelegt (da war erster Denkfehler), wird
aber nicht eingelesen, die MessageBox taucht erneut auf, und der Dialog
auch. Endlosschleife quasi.
Erst wenn ich das Programm beende und neu starte, klappts.
Da hast du ein klassisches Anti-Pattern verwendet. Man vergewaltigt das
Exception-Handling nicht für normale Programmlogik.
Du testest ob das File existiert mit File.Exists
http://msdn.microsoft.com/en-us/library/system.io.file.exists.aspx
Und je nachdem ob das true oder false ergibt öffnest du das File oder
deinen Dialog
D. I. schrieb:> Du testest ob das File existiert mit File.Exists>> http://msdn.microsoft.com/en-us/library/system.io....>> Und je nachdem ob das true oder false ergibt öffnest du das File oder> deinen Dialog
Ich kenne eigentlich auch eher den Weg, direkt zu versuchen, das File zu
öffnen. Wenn es nicht existiert, bekommt man das ja beim Öffnungsversuch
gleich mit. Wenn man das vohrer nochmal explizit abfragt, ist die
gesamte Aktion nicht mehr atomar, und es kann ein Fehlverhalten geben,
wenn zufällig gerade zwischen den beiden Teilaktionen die Datei angelegt
oder entfernt wird. Sowas wurde sogar schon als Einfallstor für
Schadsoftware verwendet.
Rolf Magnus schrieb:> Wenn man das vohrer nochmal explizit abfragt, ist die> gesamte Aktion nicht mehr atomar, und es kann ein Fehlverhalten geben,> wenn zufällig gerade zwischen den beiden Teilaktionen die Datei angelegt> oder entfernt wird.
Du sprichst in einem Anwenderprogramm von atomarer Ausführung von
Befehlen?
Davon ist überhaupt nichts atomar auch wenns nur eine Codezeile ist.
Genau das gleiche Fehlverhalten kann auch so provoziert werden, das ist
nicht mehr oder weniger zufällig.
Ins catch gehört keine normale Programmlogik.
D. I. schrieb:> Da hast du ein klassisches Anti-Pattern verwendet. Man vergewaltigt das> Exception-Handling nicht für normale Programmlogik.
Ah,.. ok, danke. Ich werde das entsprechend Umbasteln.
Ist halt so, wenn man sich das Programmieren selbst beibringt. Gibt's
eigentlich Lektüre zum Thema "sauberes Programmdesign"?
Ich hätte da allerdings nochmal ein kleines Problem, das sicherlich auch
mit Anti-Pattern oder einfach Unerfahrenheit zu tun, aber ich steh da
mal wieder da, wie der Ochs vor'm Berg.
code:
Also, Button drücken, Dialog erscheint, wird mit zwei Buttons darin (OK
& Abbrechen) geschlossen. Mit TextBoxWriteLine habe ich mir eine kleine
Methode gebastelt, um in einer TextBox eine Zeile auszugeben, quasi
meine Log-/Debug-Textbox.
Je nachdem, ob der Dialog mit Abbrechen oder mit OK geschlossen wird,
landet das Progamm im Richtigen If-then-else-Zweig, das erkenne ich an
meiner TextBox. Trotzdem wird beim Abbrechen der Wert
"Konfiguration.role" in das geändert, was nach beenden des Dialoges in
ConfigDialog.Config.role drinsteht. Obwohl im entsprechenden Zweig das
Objekt Konfiguration gar nicht neu zugewiesen wird.
Ich hoffe das war verständlich..... ich versuchs nochmal:
Dialog öffnen - Variable ConfigDialog.Config.role von z.B. "none" in
"server" ändern - Klick auf Abbrechen - Ausgabe: "Dialog abgebrochen -
server" (statt "Dialog abgebrochen - none")
Wäre schön, wenn mir da wer helfen könnte ;-)
VG
Matthias
Hallo Matthias,
du übergibst das Objekt "Konfiguration" an den "ConfigDialog" per
Reference. Das bedeutet, dass alle Änderungen an deinem "Original"
durchgeführt werden. Die Zeile "Konfiguration = ConfigDialog.Config;"
ist demnach gar nicht nötig um deinen Änderungen zu übernehmen.
Stichworte sind call by reference bzw. call by value...
MfG Sven
D. I. schrieb:> Erfahrung, Literatur und Lernen von Besseren.
Also ganz viel in Foren fragen? ;-)
Sven schrieb:> Stichworte sind call by reference bzw. call by value...
Ich übergebe also das Objekt selbst, und nicht dessen Inhalt? Alles
klar, mit deinen Stichwörtern werde ich dann (hoffentlich) schon
weiterkommen.
Danke euch allen!
Matthias S. schrieb:> D. I. schrieb:>> Erfahrung, Literatur und Lernen von Besseren.>> Also ganz viel in Foren fragen? ;-)
Nein, das würde meiner Meinung nach erst weiter hinten auf der Liste
stehen. Stackoverflow ist da eine positive Ausnahme, da kriegt man oft
kompetente Antwort, aber man sollte sich an deren Netiquette halten.
Ansonsten, in Foren wie dieses gibt es ein paar Wenige die wirklich
Ahnung von der Materie haben (wie z.B. Karl-Heinz für C++/Computational
Geometry Fragen oder Yalu wenns mal mathematisch wird) aber dafür viel
zu viele die ihre unverdauten Halbweisheiten als gottgegebenes Dogma
weiterverbreiten müssen.
keine ahnung ob es schon genannt wurde, aber try catch ist eigentlich
fürs exception handling gedacht.
bessere lösung
if(File.Exists(Path.Combine(Application.StartupPath, "settings.xml"))...
else...
So.. ich habe mich jetzt mal etwas in das Thema "call by
value/reference" eingelesen und irgendwie nicht weitergekommen.
Also folgendes meine ich Verstanden zu haben:
klassische Variablen (int, bool, string,..) sind immer Call by Value,
heißt: es wird der Wert der Variable übergeben. Soll die Referenz dazu
übergeben werden (also quasi die "Verknüpfung"), brauche ich das
Schlüsselwort "ref".
Objekte, bzw. Variablen die auf eine Klassendefinition basieren, werden
Grundsätzlich als "Call by Reference" übergeben.
Wie ich das ganze jetzt aber dazu bekomme, dass das ganze als "call bye
value" übergeben wird, habe ich allerdings noch nicht rausgefunden.
Ich poste jetzt einfach mal die ersten paar (hoffentlich relevanten)
Zeilen meines Dialogquellcodes;
1
/// <summary>
2
/// Die in diesem Dialog geladene und eingestelle Kofiguration
3
/// </summary>
4
publicSettingsConfig=newSettings();
5
6
/// <summary>
7
/// Einstellungs Dialog initalisieren und Aktuelle Konfiguration übergeben
Hallo Matthias,
du hast es eigentlich schon richtig verstanden. Zu diesem Thema gibt es
auch einen guten Artikel in der MSDN.
http://msdn.microsoft.com/de-de/library/s6938f28(VS.80).aspx
Wenn man ein Object kopieren will, meint man eigentlich klonen. Hier
wäre das Interface „ICloneable“ dein Freund. Das käme dann „per Value“
am nächsten, ist aber bäh ;-(.
Nun zu deinem eigentlichen Problem. Du hast dein Objekt "Settings" an
den "SettingsDialog" übergeben, hast sicherlich einige Auswahlfelder
oder Textfelder, wo du eine Eingabe erwartest und hast zu guter Letzt
auch einen OK- und einen Cancel-Button. Füge doch einfach im
Ereignishandler deines OK-Buttons den Code ein, der die Werte der
Eingabefelder in dein Object "Settings" übergibt. Wenn der Nutzer Cancel
drückt, wird nichts unternommen...
MfG Sven
--- schrieb:> Rolf Magnus schrieb:>> Wenn man das vohrer nochmal explizit abfragt, ist die>> gesamte Aktion nicht mehr atomar, und es kann ein Fehlverhalten geben,>> wenn zufällig gerade zwischen den beiden Teilaktionen die Datei angelegt>> oder entfernt wird.>> Du sprichst in einem Anwenderprogramm von atomarer Ausführung von> Befehlen?
Gut erkannt.
> Davon ist überhaupt nichts atomar auch wenns nur eine Codezeile ist.
Es ist ein System Call statt zwei. Das ist es, was zählt. Die Zahl der
Codezeilen hat damit nichts zu tun.
> Genau das gleiche Fehlverhalten kann auch so provoziert werden, das ist> nicht mehr oder weniger zufällig.
Dann hat aber der Betriebssystem-Kernel einen üblen Bug. Was denkst du,
was passiert, wenn der beim Öffnen einer Datei Erfolg meldet, obwohl sie
gar nicht geöffnet werden konnte, weil sie zufällig genau während des
Öffnens gelöscht wurde?
> Ins catch gehört keine normale Programmlogik.
Ich sehe da das Problem auf der anderen Seite: Die Nichtexistenz der zu
öffnenden Datei sollte eigentlich nicht zur Exception führen.
D. I. schrieb:> Da hast du ein klassisches Anti-Pattern verwendet. Man vergewaltigt das> Exception-Handling nicht für normale Programmlogik.>> Du testest ob das File existiert mit File.Exists>
Nein, das stimmt nicht. Da ein Dateizugriff immer schiefgehen kann und
man daher immer die Exceptions abfangen und entsprechend reagieren
muss, ist ein Test mittels File.Exists vorher überflüssig.
A.Hellwig schrieb:> Nein, das stimmt nicht. Da ein Dateizugriff immer schiefgehen kann und> man daher immer die Exceptions abfangen und entsprechend reagieren> muss, ist ein Test mittels File.Exists vorher überflüssig.
Moment, nicht zwei Sachen mixen. Natürlich muss man Exceptions
behandeln, aber man versteckt keine ordentliche Programmlogik im
Exceptionhandling. Exceptionhandling ist das eine, Programmlogik das
andere und daher ist es denke ich am Saubersten, dass beides gemacht
wird. Ich prüfe erst mit File.Exists und wenn das fehlschlägt fahre ich
im else-Teil mit Programmlogik fort und im Erfolgfall öffne ich die
Datei und kümmere mich an dieser Stelle um potenzielle Exceptions.
A.Hellwig schrieb:> D. I. schrieb:>> Man kann in C# keine Objekttypen by value übergeben, die werden immer by>> reference übergeben>> Falsch, siehe> http://msdn.microsoft.com/en-us/library/vstudio/14akc2c7.aspx.
Öhm wo widerspricht das meiner Aussage? Ich habe nicht gesagt, dass man
primitive Typen nicht auch als Referenz übergeben kann.
Nun gut aber structs sind auch Wertetypen, so gesehen...