Allokation im Speicher von weitergegebenen Variablen

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

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

    ErfinderDesRades schrieb:

    Ich würds allerdings ohne machen - weil je weniger Variablen desto besser
    Stichwort meinerseits: DisposeAndNullify-Extension
    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.

    VaporiZed schrieb:


    Haudruferzappeltnoch schrieb:

    was ist wenn ich hier CreateSqlCommand aufrufe
    Dann bekommt cmd einen neuen Wert.

    Ich meinte was ist der neue Wert? Ist das Sql.cmd oder eine Kopie von Sql.cmd?

    Was bedeutet denn das ?.Dispose? Ich verstehs jetzt so als ersetzt der If Not is Nothing Then

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

    Ja, das Fragezeichen ersetzt das If X IsNot Nothing Then
    Somit If X IsNot Nothing Then X. Dispose kann man als X?.Dispose schreiben.

    Der neue cmd-Wert ist ein neues Objekt (wahrscheinlich) mit gleichen Werten wie der cmd-Wert vorher. Damit könnte man es als Kopie bezeichnen.
    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.

    Haudruferzappeltnoch schrieb:

    cmd bekommt ja den Wert von Sql.cmd
    ?( In welcher Zeile? Das entstehende Objekt ist durch sql.cmd und den Rückgabewert bzw. die aufnehmende Variable erreichbar, weil alle Variablen auf das Objekt verweisen/zeigen. Letztenendes werden AFAIK intern Zeiger auf das eigentliche Objekt hin- und hergereicht. Das Objekt selbst ist nicht direkt fassbar.
    Also

    VB.NET-Quellcode

    1. Sub Main
    2. Dim SqlInstance = New Sql()
    3. Dim Foo = SqlInstance.CreateSqlCommand()
    4. End Sub
    5. Friend Class Sql
    6. Private con as SqlConnection
    7. Friend cmd as SqlCommand
    8. ...
    9. Friend Sub New()
    10. con = New SqlConnection(ConnString)
    11. End Sub
    12. Friend Function CreateSqlCommand() as SqlCommand
    13. cmd = New SqlCommand(SqlString, con)
    14. Return cmd
    15. End Function
    16. End Class

    Das in Zeile#15 erschaffene Objekt ist mittels Verwendung von cmd (Zeile#15) und Foo (Zeile#3) ansprechbar. Beide Variablen ermöglichen Zugriff auf das selbe Objekt. Aber effektiv werden da nur Zeiger auf das Objekt weitergereicht/kopiert. Das Objekt wird selbst nicht kopiert. Ändert man mithilfe von Foo das Objekt, ist das in cmd sofort sichtbar.

    Erklärung ausreichend oder noch unklar?
    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.
    Ja das ist was ich meine. Bzw. habe ich schon wieder vergessen das abhängig von Referenztyp und Datentyp zu sehen.
    Also liegt das nun am Return oder daran, dass das Objekt ein Referenztyp ist?
    Also wenn ich ein Argument übergebe, dann kann das als Structure ByVal oder ByRef übergeben werden. Als Class wird es immer ByRef übergeben.
    Die Auswahl habe ich bei Return ja nicht. Würde eine Structure auch als Zeiger zurückgegeben werden? Oder hätte in dem Fall Foo seine eigenen Daten?

    ISliceUrPanties schrieb:

    Hier mal zwei Videos, die den GC und das Dispose-Pattern, wie ich finde, ziemlich gut erklären.
    Ich mag die Quatschköppe nicht 15min lang angucken müssen, und aufgrund meines schlechten Englisches nur bruchstückweise verstehen.
    Gibts nicht iwas, was man lesen kann, und ggfs. auch nachlesen (mw. auch Englisch)?

    Haudruferzappeltnoch schrieb:

    liegt das nun am Return oder daran, dass das Objekt ein Referenztyp ist?
    Am Referenztyp. Wenn man schreibt:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Friend Class FrmMain
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim NewFoo = New Foo
    4. Dim NewBaz = NewFoo.Bar
    5. NewBaz.Buzz = 2
    6. Console.WriteLine("Buzz in FrmMain: " & NewBaz.Buzz)
    7. NewFoo.ShowBaz()
    8. End Sub
    9. End Class
    10. Friend Class Foo
    11. Property MyBaz As Baz
    12. Function Bar() As Baz
    13. MyBaz = New Baz With {.Buzz = 1}
    14. Return MyBaz
    15. End Function
    16. Sub ShowBaz()
    17. Console.WriteLine("Buzz in Me: " & MyBaz.Buzz)
    18. End Sub
    19. End Class
    20. Structure Baz
    21. Property Buzz As Integer
    22. End Structure
    sieht man, dass bei Datentypen die Eigenschaften geändert werden können, ohne dass andere was davon mitbekommen.

    Es werden also Kopien erstellt. Probiert man das mit einem Referenztyp, geht das so nicht, da ergibt sich für Buzz jeweils 2:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Friend Class FrmMain
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim NewFoo = New Foo
    4. Dim NewBaz = NewFoo.Bar
    5. NewBaz.Buzz = 2
    6. Console.WriteLine("Buzz in FrmMain: " & NewBaz.Buzz)
    7. NewFoo.ShowBaz()
    8. End Sub
    9. End Class
    10. Friend Class Foo
    11. Property MyBaz As Baz
    12. Function Bar() As Baz
    13. MyBaz = New Baz With {.Buzz = 1}
    14. Return MyBaz
    15. End Function
    16. Sub ShowBaz()
    17. Console.WriteLine("Buzz in Me: " & MyBaz.Buzz)
    18. End Sub
    19. End Class
    20. Class Baz
    21. Property Buzz As Integer
    22. End Class



    Aber: mit ByVal/ByRef hat das nix zu tun, davon bin ich nämlich auch wie Du lange falsch ausgegangen. Es gibt Situationen, in denen man einen Referenztypen mittels ByRef an eine Methode übergeben muss, nämlich wenn man die "Zeigervariable" selbst ändern will, siehe oben mein Link zu DisposeAndNullify.

    Zu den Videos schreib ich später vielleicht noch was, bin gestern dabei eingeschlafen.
    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.

    ErfinderDesRades schrieb:

    und aufgrund meines schlechten Englisches nur bruchstückweise verstehen. Gibts nicht iwas, was man lesen kann, und ggfs. auch nachlesen (mw. auch Englisch)?
    Ich fand die Videos gar nicht so schlecht, vor allem auch weil keine Inkonsistenz drin war. Am Ende war alles nochmal so klar geworden wie ich es durch euch in etwa nachvollzogen habe.
    Ich kann gerne mal aufschreiben, was die Videos wie vermitteln, vielleicht haben andere Leute auch ein Problem mit der Sprachbarriere.

    ErfinderDesRades schrieb:

    Gibts nicht iwas, was man lesen kann, und ggfs. auch nachlesen (mw. auch Englisch)?

    Hm, ich kenne leider keine guten deutschen Resourcen zu dem Thema - es wird häufig das Thema nur Oberflächlich betrachtet (oder sind steinalt). Grundsätzlich ist für mich immer die MS Doku eine gute Anlaufstelle - da MS halt der Hersteller ist; z.B. Garbage Collection - Fundamentals.

    ISliceUrPanties schrieb:

    Grundsätzlich ist für mich immer die MS Doku eine gute Anlaufstelle
    jo, das ist doch was. Und daneben findet sich ja auch diese Erklärung: What is "managed code"?
    Aufs Disposen bezogen bestätigt das meine Ansicht: Im Dispose() sollte man aufräumen, was der GC nicht aufräumen kann.
    Das sind v.a. drei Dinge:
    1. Disposable Objekte (die sind managed, aber kanner trotzdem nur teilweise bereinigen)
    2. InterOp-Krimskrams (ebenfalls managed, aber kanner trotzdem nur teilweise bereinigen)
    3. Handles, die man sich evtl. per PInvoke geholt hat (echt unmanaged, weil son IntPointer zeigt auf iwas)
    Und nachwievor ists mir höchst ungeheuer, GC.SuppressFinalize(Me) aufzurufen.
    Methoden wie Excel.Quit benutzt der GC nicht.
    Das heißt das muss man dem beibringen, oder man verlässt sich drauf dass z.B. Excel wirklich immer vom Programmierer (und vom Prorgammablauf) fachgerecht entsorgt wird.

    Das Dispose-Pattern bringt es dem GC also explizit bei um den Fall, das man das vergisst, abzudecken. Und dann ist SuppressFinalize notwendig, damit es keine Exception gibt, wenn man dann doch selbst aufräumt.
    Der Fehler wird nicht durch Excel verursacht, sondern weil der Finalizer der Bestandteile einer Klasse vor dem Finalizer der Klasse läuft und dann für die Bestandteile kein Dispose mehr aufgerufen werden kann.
    Excel wird auch geprüft vorher. Genauso wie man das ComObject noch released anschließend.

    Das Dispose-Pattern versucht das alles zu bedenken. Es geht auch anders. Aber warum sich selbst eine andere Logik ausdenken, die die gleichen Fälle abdeckt?
    Das hier ist wie ichs jetzt mitgenommen habe aus den Videos. Da wird das einmal gezeigt warum Finalizer und Dispose sich beißen, wenn man Ressourcen hat die der GC nicht kennt.