Using / End Using und der GC

  • VB.NET
  • .NET (FX) 3.0–3.5

Es gibt 45 Antworten in diesem Thema. Der letzte Beitrag () ist von hirnwunde.

    Using / End Using und der GC

    Hiho,

    Folgender Code:

    VB.NET-Quellcode

    1. Public Function getBoxNr(ByVal txlcode As String) As UInteger
    2. Dim iReturn As UInteger = 0
    3. Using conn As New MySqlConnection(connstring), cmd As New MySqlCommand
    4. cmd.Connection = conn
    5. cmd.CommandText = "SELECT * FROM `InterneBoxen` WHERE " _
    6. + "p1 = @txlcode OR p2 = @txlcode OR " _
    7. + "p3 = @txlcode OR p4 = @txlcode OR " _
    8. + "p5 = @txlcode OR p6 = @txlcode OR " _
    9. + "p7 = @txlcode OR p8 = @txlcode OR " _
    10. + "p9 = @txlcode;"
    11. cmd.CommandType = CommandType.Text
    12. cmd.Parameters.AddWithValue("@txlcode", txlcode)
    13. Try
    14. conn.Open()
    15. Dim reader As MySqlDataReader = cmd.ExecuteReader()
    16. If reader.HasRows Then
    17. iReturn = CUInt(reader.Item("BoxNrIntern"))
    18. End If
    19. Catch ex As Exception
    20. MessageBox.Show("getBoxNr: " + CrLf + ex.Message)
    21. Finally
    22. cmd.Dispose()
    23. conn.Close()
    24. End Try
    25. End Using
    26. Return iReturn
    27. End Function

    Folgende Fragen: ;)

    Ist der Finaly-Block überflüssig, weil End Using sowieso schon aufräumt
    oder werden die Objekte erst beim verlassen der Funktion ins Nirvana verfrachtet?
    Wo wird

    hirnwunde schrieb:

    VB.NET-Quellcode

    1. cmd
    deklariert und instanziiert?
    Mach das doch auch lokal, auch in einem Using-Block.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Grundsätzlich solltest du eine geöffnete Verbindung zur DB immer mit close wieder schließen.

    Eigentlich sollte durch den End Using Befehl alles freigegeben werden was verwendet wurde also theoretisch auch die Datenbankverbindung. Aber desswegen ist es nicht gleich im Datennirvana verschwunden ... es wird dadurch für den GC zum Abschuss freigegeben. Weg ist es erst wenn der GC das nächste mal aufräumt

    slice schrieb:

    am Ende
    OK, ich hasse diese multiplen Usings.
    @hirnwunde Using und das was über und im Try-Block steht.
    Feddich.
    Und wenn es knallt, fängst Du genau diese Exception ab.

    VB.NET-Quellcode

    1. Public Function getBoxNr(ByVal txlcode As String) As UInteger
    2. Dim iReturn As UInteger = 0
    3. Using conn As New MySqlConnection(connstring), cmd As New MySqlCommand
    4. cmd.Connection = conn
    5. cmd.CommandText = "SELECT * FROM `InterneBoxen` WHERE " _
    6. + "p1 = @txlcode OR p2 = @txlcode OR " _
    7. + "p3 = @txlcode OR p4 = @txlcode OR " _
    8. + "p5 = @txlcode OR p6 = @txlcode OR " _
    9. + "p7 = @txlcode OR p8 = @txlcode OR " _
    10. + "p9 = @txlcode;"
    11. cmd.CommandType = CommandType.Text
    12. cmd.Parameters.AddWithValue("@txlcode", txlcode)
    13. conn.Open()
    14. Dim reader As MySqlDataReader = cmd.ExecuteReader()
    15. If reader.HasRows Then
    16. iReturn = CUInt(reader.Item("BoxNrIntern"))
    17. End If
    18. conn.Close()
    19. End Using
    20. Return iReturn
    21. End Function

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    OK, ich hasse diese multiplen Usings.
    Mach halt die GlotzBöbbel auf beim Code-Lesen ;) . Das Prob tritt ja eh nur in ForenPosts auf - in einem VisualStudio zeigtes dir ja sofort, wo der Frosch die Locken hat.


    Cell schrieb:

    Eigentlich sollte durch den End Using Befehl alles freigegeben werden
    Ja, und das tut es auch.

    Cell schrieb:

    Aber desswegen ist es nicht gleich im Datennirvana verschwunden
    Falsch. Natürlich ist eine disposete Connection im Daten-Nirvana.
    Je nach Implementation wird für ein disposetes Objekt der GC sogar suspendiert - weil das Dispose hat bereits vollständig aufgeräumt.

    ErfinderDesRades schrieb:

    Und der Catch ist schlimmer noch als überflüssig

    Nunja.
    Bei einer Subroutine würde ich zustimmen, da dort wirklich Sachen schief gehen können.
    Bei (meiner) Funktion aber wird ja trotz der Exception ein Rückgabewert geliefert.
    Dieser ist 0.
    Wenn ich jetzt ohne try/catch ran gehe, könnte es passieren, dass der Server nicht erreichbar
    ist und ich den Rückgabewert 0 erhalte, ohne zu wissen, das die Abfrage garnicht statt fand.
    Dann gehe ich davon aus, dass das Bauteil in keiner Box ist, obwohl dies ja der Fall sein könnte.

    Aber auch hier mag mir meine Unwissenheit etwas vorgaukeln.

    hirnwunde schrieb:

    ohne zu wissen, das die Abfrage garnicht statt fand.
    Dann gib bei einer Exception -1 zurück.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    hirnwunde schrieb:

    Bei (meiner) Funktion aber wird ja trotz der Exception ein Rückgabewert geliefert.
    Ja, und das ist ein DesignFehler.

    hirnwunde schrieb:

    Bei einer Subroutine würde ich zustimmen
    ich würde dein getBoxNr() aber unbedingt als SubRoutine bezeichnen , oder wie definierst du "SubRoutine"?

    Jedenfalls diese (Sub-)Routine ist der falsche Ort für ein Retry, wenn du denn imstande bist, eines zu programmieren.
    Bist du nicht dazu imstande, darfst du den Catch erst recht nicht hinschreiben.

    Also wenn catchen, dann woanders.
    Und differenzierter Catchen, als einfach die allgemeine Exception.

    ErfinderDesRades schrieb:

    oder wie definierst du "SubRoutine"?


    Eine Subroutine ist für mich eine Funktion ohne Rückgabewert.

    Wenn ich in meinem Programm eine Subroutine aufrufe, weiss ich nicht, ob das,
    was gemacht werden sollte, gemacht wurde.
    Ausser ich setze irgendwelche globalen Flags, die in der Sub geflaggt werden
    und ich in meinem aufrufenden Code schaue, ob das Flag richtig gesetzt
    wurde.

    Mit einer Funktion habe ich ein Rückgabewert, woraus ich ersehen kann, ob das,
    was ich vor hatte, gemacht wurde.

    RodFromGermany schrieb:

    Dann gib bei einer Exception -1 zurück.


    Würde es nicht auch gehen, wenn ich den Rückgabewert schon mit -1 initialisiere?

    VB.NET-Quellcode

    1. Public Function getBoxNr(ByVal txlcode As String) As Integer
    2. Dim iReturn As Integer = -1
    3. Using conn As New MySqlConnection(connstring), cmd As New MySqlCommand
    4. cmd.Connection = conn
    5. cmd.CommandText = "SELECT * FROM `InterneBoxen` WHERE " _
    6. + "p1 = @txlcode OR p2 = @txlcode OR " _
    7. + "p3 = @txlcode OR p4 = @txlcode OR " _
    8. + "p5 = @txlcode OR p6 = @txlcode OR " _
    9. + "p7 = @txlcode OR p8 = @txlcode OR " _
    10. + "p9 = @txlcode;"
    11. cmd.CommandType = CommandType.Text
    12. cmd.Parameters.AddWithValue("@txlcode", txlcode)
    13. conn.Open()
    14. Dim reader As MySqlDataReader = cmd.ExecuteReader()
    15. If reader.HasRows Then
    16. iReturn = CUInt(reader.Item("BoxNrIntern"))
    17. Else
    18. iReturn = 0
    19. End If
    20. conn.Close()
    21. End Using
    22. Return iReturn
    23. End Function

    @Noyne: Manche Klassen belegen Resourcen, die der GC nicht korrekt freigeben kann. Solche Klassen implementieren dann das IDisposable-Interface, und du kannst du dir ein Memory-Leak einfangen, wenn du diese nach Gebrauch nicht disposest.
    Bei anderen Klassen ist der Dispose-Aufruf "nur" eine Optimierung. Also der GC kanns schon freigeben, allerdings erst, wenn der Objekt-Zyklus soweit ist (da steckt iwie ein listiger Algo hinter).

    @Hirnwunde: Ok, was du als SubRoutine bezeichnest, bezeichne ich als Sub.
    Hat auf meine Ausführungen keine Auswirkung: Es ist ein Fehl-Design, Exceptions durch Rückgabewerte "substituieren" zu wollen.
    Weil Rückgabewerte können ignoriert werden - Exceptions dürfen aber nicht ignoriert werden.

    Übrigens das Close kannste dir auch sparen, dank des Using-Blocks.

    Ach, und jetzt ist der TryCatch weg :thumbup: - da kann man sich natürlich ausserdem sparen, den Return-Wert iwie zu initialisieren - im Fehlerfall gibts keinen Return-Wert, sondern Exception.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Demnach besteht auch noch ein Unterschied zwischen Sub und Subroutine?

    Mein Fehler ... hab grad nochmal bisserl gesucht und ja. Ich ahb es nur falsch bezeichnet.
    Richtige Bezeichnung wäre Sub-Prozedur. (siehe msdn.microsoft.com/de-de/library/831f9wka.aspx)

    Und ja ... ich fange an zu verstehen, wann ein Try/Catch sinnvoll wäre.
    Ganz ohne Try/Catch springt der JIT-Debugger an.
    Und dieser gibt mir ja schon ausreichend Informationen, was schief lief.

    Gehe ich recht in der Annahme, das:

    VB.NET-Quellcode

    1. Public Function getBoxNr(ByVal txlcode As String) As UInteger
    2. Dim iReturn As UInteger = 0
    3. Using conn As New MySqlConnection(connstring), cmd As New MySqlCommand
    4. cmd.Connection = conn
    5. cmd.CommandText = "SELECT * FROM `InterneBoxen` WHERE " _
    6. + "p1 = @txlcode OR p2 = @txlcode OR " _
    7. + "p3 = @txlcode OR p4 = @txlcode OR " _
    8. + "p5 = @txlcode OR p6 = @txlcode OR " _
    9. + "p7 = @txlcode OR p8 = @txlcode OR " _
    10. + "p9 = @txlcode;"
    11. cmd.CommandType = CommandType.Text
    12. cmd.Parameters.AddWithValue("@txlcode", txlcode)
    13. Try
    14. conn.Open()
    15. Dim reader As MySqlDataReader = cmd.ExecuteReader()
    16. If reader.HasRows Then
    17. iReturn = CUInt(reader.Item("BoxNrIntern"))
    18. End If
    19. Catch mysqlex As MySqlException
    20. Select Case mysqlex.ErrorCode
    21. Case 1045 : MessageBox.Show("Ungültiger Benutzername oder falsches Passwort")
    22. Case 1149 : MessageBox.Show("Syntax-Fehler im SQL-Query, Du Honk!")
    23. End Select
    24. End Try
    25. End Using
    26. Return iReturn
    27. End Function

    in Ordnung wäre? (wenn ich es denn brauchen würde um speziell auf MySQl-Errors zu reagieren)
    Von dem, was Du schrubtest hab ich einiges gelesen, aber noch nicht vollends verstanden ;)

    Und ja ... das eine Ausgabe einer Fehlermeldung keine Fehlerbehandlung darstellt, ist mir klar geworden.
    Das Beispiel eben sollte nur verdeutlichen, um was es ging.
    Im Falle von Case 1045 hätte ich ebensogut ein Dialogfeld aufploppen lassen können, welche neue Zugangsdaten erfragt.
    Das wäre dann eine Fehlerbehandlung, oder?
    ja, das wäre eine Fehlerbehandlung.
    Aber spiel das mal durch - das wird noch bisserl komplizierter, denn du musst was coden, wo der User zB 3mal was falsches eingeben kann, bevor er gebannt wird oder sowas.

    und Case 1149 ist ja genau die Quatsch-Messagebox mit Schuss ins Knie: Wenn der Honk (wer kann damit gemeint sein? ;) ) einen Sql-Query-Fail verzapft hat, dann soller bitte seinen Code korrigieren - und dabei hilft ihm der Debugger besser als die dumme Messagebox.

    hirnwunde schrieb:

    mit -1 initialisiere?
    Wird immer überschrieben.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ErfinderDesRades schrieb:

    ist ja genau die Quatsch-Messagebox mit Schuss ins Knie


    Wie schon oben angemerkt ... die msgboxes waren nur so dahingespuckt ... da würde ebenso eine Dialogbox aufgehen, wo der SQL-Query korrigiert werden kann.

    Aber ja ... es wird immer klarer.
    Wen ich mit Try/Catch einen Fehler abfangen will, wird der JIT-Debugger komplett aussen vor gelassen.
    Und alle auftretenden Ausnahmen, die nicht im Catch abgefangen wurden, werden verschluckt.
    Diese Situation ist natürlich wirklich nicht empfehlenswert.

    ErfinderDesRades schrieb:

    wo der User zB 3mal was falsches eingeben kann

    Nunja ... explizit dieser Fall ist ja eher Aufgabe des Server. mMn ...

    RodFromGermany schrieb:

    Wird immer überschrieben.

    Bezug nehmend auf den Code aus Post 12:
    Hmm ... wenn in Zeile 14 die Verbindung schon nicht aufgebaut werden kann,
    kann er doch nicht in Zeile 17 oder 19 den Wert ändern.
    Oder verstehe ich da etwas falsch?

    ErfinderDesRades schrieb:

    Manche Klassen belegen Resourcen
    Hab die Seite aufm MSDN gefunden msdn.microsoft.com/de-de/libra…o/b1yfkh5e(v=vs.100).aspx und werd' mich da mal ein bisschen schlaulesen ... Danke erstma für die Kurzerklärung, aber ich glaub', ich brauch' das ausführlicher ^^
    Your computer is running... You better go chase it! :P :D