Was ist/bedeutet SqlConnection.Open

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 32 Antworten in diesem Thema. Der letzte Beitrag () ist von Haudruferzappeltnoch.

    Mein Nichtinformatikerverständnis wiedergebend:

    Das Verhalten von Werte- und Referenztypen bei ByVal und ByRef ist etwas schwer zu erfassen.

    ByRef führt dazu, dass derselbe Speicherplatzinhalt verwendet wird. Diuretisches Beispiel:

    VB.NET-Quellcode

    1. Private Sub Foo()
    2. Dim X As Integer = 5
    3. NennMirDieAdresseAnDerFolgendeVariableGepeichertIst(X) 'Ergebnis &H0815ABBA
    4. SubMitByVal(X)
    5. SubMitByRef(X)
    6. End Sub
    7. Private Sub SubMitByVal(Variable As Integer)
    8. NennMirDieAdresseAnDerFolgendeVariableGepeichertIst(Variable) 'Ergebnis &H423A5EE
    9. End Sub
    10. Private Sub SubMitByRef(ByRef Variable As Integer)
    11. NennMirDieAdresseAnDerFolgendeVariableGepeichertIst(Variable) 'Ergebnis &H0815ABBA
    12. End Sub

    Bei Wertetypen:
    Bei ByRef wird die Speicheradresse an die Sub übermittelt und so derselbe Speicherinhalt innerhalb der Sub verwendet. Demenstprechend wird der Inhalt der übergebenden Variable in/aus Foo verändert, wenn man die Variable in der Sub ändert.
    Bei SubMitByVal wird stattdessen der Wert der Variablen übergeben, also eine neue Variable angelegt und mit dem gleichen Wert versehen wie die Originalvariable. Es gibt jetzt also 2 Variablen mit dem gleichen Wert im Speicher. Ändert man jetzt den Wert der einen, ist das der anderen egal.

    Nun aber Refenztypen:
    Da werden unabhängig davon, ob man ByVal oder ByRef übergibt, nicht die Objekte an sich (weil die sehr groß sein können), sondern intern deren Speicheradressen übergeben. Und damit arbeitet die aufgerufene Sub weiter. Also wird in der Sub somit immer automatisch auf das Originalobjekt zugegriffen. Eben weil keine Kopie angelegt wird wie bei Wertetyp+ByVal. Dadurch scheint es erstmal egal zu sein, ob man eine Referenztypobjektinstanz per ByVal oder per ByRef übergibt. Aber es gibt ein paar Fälle, in denen man auch solch ein Objekt per ByRef übergeben muss.

    Und jetzt eben noch:
    Wird ein Referenztypinstanz wie ne SqlConnection (da der Typ eine Klasse ist) in einer Sub erstellt, wird diese solange am Leben erhalten, wie sie gebraucht wird. Wird die Instanz an eine aufrufende Methode zurückgegeben, wird dem GarbageCollector klargemacht, dass das Teil wohl noch weiterverwendet wird und nicht vernichtet werden darf. Erst wenn es keine gültige Variable mehr gibt, die auf diese SqlConnection verweist, wird sie zum Abschuss freigegeben.
    Deine ByRef-Übergabe (oder eben Byval-Übergabe) der SqlConnection an eine Sub und die dortige Disposeierung ist aber dem obigen Verhalten geschuldet: Das Originalobjekt wird hier plattgemacht, weil man dieses hier an der Angel hat. Es wird bei Subaufruf keine Kopie erstellt.

    In Summe: Zwei Verhaltensweisen, die verhaltenstechnisch ähnlich aussehen, aber andere Gründe haben.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Danke für die Erklärung, finde ich gut nachvollziehbar. Der Punkt mit dem Speicherplatz ist denke ich der Relevanteste. Ich dachte nämlich ByVal, ByRef und FunctionReturnte Variable kriegen alle einen eigenen Speicherplatz. Aber jetzt ist auch klar, das erscheint natürlich eine riesen Verschwendung. So tief konnte ich noch nicht schauen.
    Ich sag nur immer wieder: Lies ein Buch.
    Du hast hier zwei ganz wichtige Grundlagen-Themen berührt:
    • ByVal/ByRef - Parameter-Übergabe
    • Referenz-/Wert-Datentypen
    Das eine hat mit dem anderen nicht wirklich was zu tun. Eiglich wäre besser, die Themen in getrennten Threads zu behandeln.
    Und zwar das zweite zuerst, denn sowohl Referenz- als auch Wert-Datentypen werden als Parameter an Methoden übergeben (und zwar jeweils mal ByVal, mal ByRef).
    Es geht auch an keiner Stelle um Verschwendung von Speicherplatz.
    Es geht darum, ob man mit "Zeigern" (Referenzen) auf Speicherplatz arbeitet oder mit Speicherplatz-Kopien.
    Beides ist je nach Umständen das angemessenere.

    Gibts da eiglich nix im Allgemein-Tutorial-Bereich?
    @Haudruferzappeltnoch Verständlicher wird es vielleicht, wenn Du ein Array oder eine List(Of T) mit ByRef oder ByVal übergibst.
    Überlege zuerst, was da passiert, bevor Du den Code ausführst:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    2. Dim ll = New List(Of Integer) From {1, 2, 3, 4, 5}
    3. DoIt1(ll)
    4. MessageBox.Show(ll.ToString())
    5. DoIt2(ll)
    6. MessageBox.Show(ll.ToString())
    7. End Sub
    8. Sub DoIt1(ByVal li As List(Of Integer))
    9. li = Nothing
    10. End Sub
    11. Sub DoIt2(ByRef li As List(Of Integer))
    12. li = Nothing
    13. End Sub
    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!
    Ja das Verhalten, was dieser Code zeigt, war mir schon lange bewusst. MessageBox Nr 2 hat keinen String mehr drin und es gibt ne Exception, ich denke mal weil Nothing keine .ToString Methode hat

    Aber das gibt ja keinen Rückschluss auf die verwendeten Speicherplätze. Wir haben es ja bereits klären können, bei ByVal zwei (nichtmal das immer) bei ByRef einer.

    Danke euch

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Haudruferzappeltnoch schrieb:

    weil Nothing keine .ToString Methode hat
    Klar.
    Die Methode heißt: "Lernen durch Schmerz". Eine exception hat, denke ich, einen größeren Lerneffekt als eine Ausgabe in einem Label. ;)
    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!
    Ich hab hier mal ein Beispiel, wo ich einen DataAdapter aus einer anderen Klasse bekomme, wie Dispose ich dort denn jetzt im Nachhinein die Connection wieder?
    Weil sie lokal definiert ist, kann ich die ja nicht ansprechen. Ich dachte vielleicht muss ich noch eine Dispose Sub in der DBZugriff Klasse basteln, aber dann hab ich immer noch die Connection lokal, also müsste ich die auf Klassenebene definieren?

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    3. Dim DBZ As New DBZugriff("sql")
    4. DBZ.DB1Adapter.Fill(DS1.dt1)
    5. End Sub
    6. End Class
    7. Friend Class DBZugriff
    8. Private SqlString As String
    9. Friend Sub New(sql As String)
    10. SqlString = sql
    11. End Sub
    12. Friend Function DB1Adapter() As SqlDataAdapter
    13. Dim cn As New SqlConnection("bla")
    14. Dim da As New SqlDataAdapter(SqlString, cn)
    15. Return da
    16. End Function
    17. End Class

    Korrekt. Du könntest zwar der DBZugriff-Klasse das Disposen beibringen, indem Du das IDisposable-Interface implementierst. Dann kannst Du zwar lokal einen Using-Block nutzen (also in Deinem Beispiel in Form1_Load) und wenn Du das vergisst, könnte Dich ggf. VS darauf hinweisen, dass da ein Using/Dispose fehlt. Aber wenn Du es klassenweit machst, musst Du das Objekt entweder im Form-Disposing-Teil disposen oder Dich im FormClosing-EventHandler drum kümmern. Aber drum kümmern musst Du Dich immer selbst.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Sry da komm ich nicht hinterher, mit Objekt meinst du jetzt die Instanz DBZ?

    Wenn ich Using im .Load nutze, dann könnte ich das höchstens mit DBZ selbst tun oder? Das erwischt dann auch die Connection cn?
    Wie kann ich denn sehen dass etwas richtig disposed ist?

    Das Closing-Event ist nicht gut genug. Das wird in nem Programm laufen, das sehr lange in Betrieb ist. Ich denke die Verbindung sollte nach ihrem Nutzen Disposed werden.

    Die IDisposable Schnittstelle liefert sowas:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private disposedValue As Boolean ' Dient zur Erkennung redundanter Aufrufe.
    2. ' IDisposable
    3. Protected Overridable Sub Dispose(disposing As Boolean)
    4. If Not disposedValue Then
    5. If disposing Then
    6. ' TODO: verwalteten Zustand (verwaltete Objekte) entsorgen.
    7. End If
    8. ' TODO: nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() weiter unten überschreiben.
    9. ' TODO: große Felder auf Null setzen.
    10. End If
    11. disposedValue = True
    12. End Sub
    13. ' TODO: Finalize() nur überschreiben, wenn Dispose(disposing As Boolean) weiter oben Code zur Bereinigung nicht verwalteter Ressourcen enthält.
    14. 'Protected Overrides Sub Finalize()
    15. ' ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in Dispose(disposing As Boolean) weiter oben ein.
    16. ' Dispose(False)
    17. ' MyBase.Finalize()
    18. 'End Sub
    19. ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    20. Public Sub Dispose() Implements IDisposable.Dispose
    21. ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in Dispose(disposing As Boolean) weiter oben ein.
    22. Dispose(True)
    23. ' TODO: Auskommentierung der folgenden Zeile aufheben, wenn Finalize() oben überschrieben wird.
    24. ' GC.SuppressFinalize(Me)
    25. End Sub


    Das wird ja kompliziert

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Haudruferzappeltnoch schrieb:

    mit Objekt meinst du jetzt die Instanz DBZ?
    korrekt

    Haudruferzappeltnoch schrieb:

    Wenn ich Using im .Load nutze, dann könnte ich das höchstens mit DBZ selbst tun oder? Das erwischt dann auch die Connection cn?
    cn erwischt es, wenn Du die IDisposable-Schnittstelle entsprechend implementierst (s.u.)

    Haudruferzappeltnoch schrieb:

    Wie kann ich denn sehen dass etwas richtig disposed ist?
    Öhm … indem Du Deinen Code anschaust :huh:

    Haudruferzappeltnoch schrieb:

    Ich denke die Verbindung sollte nach ihrem Nutzen Disposed werden
    Dann tu das. Entweder mit einem Using-Block oder, wenn Du das Objekt länger brauchst, durch explizites disposen, also DBZ.Dispose aufrufen.

    Haudruferzappeltnoch schrieb:

    Das wird ja kompliziert

    Nee, kopliziert sieht es nur aus. Wenn Du alle Kommentare entfernst, kannst Du das zusammendampfen:

    VB.NET-Quellcode

    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    2. Using DBZ As New DBZugriff("sql")
    3. DBZ.DB1Adapter.Fill(DS1.dt1)
    4. End Using
    5. End Sub
    6. End Class
    7. Friend Class DBZugriff : Implements IDisposable
    8. Private SqlString As String
    9. Private disposedValue As Boolean
    10. Private cn As New SqlConnection("bla")
    11. Private da As New SqlDataAdapter(SqlString, cn)
    12. Friend Sub New(sql As String)
    13. SqlString = sql
    14. End Sub
    15. Friend Function DB1Adapter() As SqlDataAdapter
    16. Dim cn As New SqlConnection("bla")
    17. Dim da As New SqlDataAdapter(SqlString, cn)
    18. Return da
    19. End Function
    20. Protected Overridable Sub Dispose(disposing As Boolean)
    21. If disposedValue Then Return
    22. If disposing Then
    23. cn.Dispose() : cn = Nothing
    24. da.Dispose() : da = Nothing
    25. End If
    26. disposedValue = True
    27. End Sub
    28. Public Sub Dispose() Implements IDisposable.Dispose
    29. Dispose(True)
    30. GC.SuppressFinalize(Me)
    31. End Sub
    32. End Class

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.