Aufruf von Destruktoren in C# **gelöst**



  • Hi Leute,

    ich habe ein Klasse im C++/CLI erstellt und über eine Dll exportiert.

    Die Klasse instanziere ich wie Folgt:

    public partial class Form1 : Form
        {
            DllDotNet.CReadWrapper Read;
    
            public Form1()
            {
                InitializeComponent();
                Read = new DllDotNet.CReadWrapper();
            }
    

    Diese Klasse hat einen Destruktor. Jetzt steht in der MSDN das dieser automatisch gerufen wird. (http://msdn.microsoft.com/de-de/library/66x5fx1b(VS.80).aspx)

    Wenn ich einen Breakpoint in dem Destruktor mache hält er nicht an. Warum?

    MfG



  • Weil managed Resourcen vom GC verwaltet werden und der GC "irgendwann" dein "Destruktor" Code ausführt. Falls Du also einen deterministischen "Destruktor" Aufruf benötigst, musst Du IDisposable implementieren.

    http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

    In C# kannst Du using benutzen, in C++/CLI kannst Du delete (auf ein managed Handle) benutzen.

    Simon



  • meine Klasse ist ja eine managed Klasse. Das heißt für mich der Destruktor müßte irgendwann gerufen werden wenn ich das Programm schließe bevor es weg ist.

    Wenn ich jetzt einen Breakpoint im Destruktor setze dann hälte er dort nicht an, obwohl er nach deiner aussage anhalten müsste.

    Woran könnte dies liegen?

    MfG



  • Ich präzisiere meinen Post noch etwas hinsichtlich C++/CLI:
    Wenn Du dort einen Destruktor impl., dann wird automatisch IDisposable impl.

    D.h. in C# reicht es dann, einfach Dispose() aufzurufen oder using zu verwenden.

    meine Klasse ist ja eine managed Klasse. Das heißt für mich der Destruktor müßte irgendwann gerufen werden wenn ich das Programm schließe bevor es weg ist.

    Wenn ich jetzt einen Breakpoint im Destruktor setze dann hälte er dort nicht an, obwohl er nach deiner aussage anhalten müsste.

    Woran könnte dies liegen?

    MfG

    Ja, der Destruktor wird nicht aufgerufen. Ist so. Generell kann man sagen, dass wenn eine Klasse IDisposable impl. dann muss man auch Dispose() aufrufen.

    Simon



  • OK

    also Dispose rufe ich so

    Read.Dispose()
    

    Wie funktioniert das mit using?

    Generell ist das ja aber ein Problem, da C# Programmierer sich ja im normalfall nicht um den Destrukto kümmern, da der ja automatisch gerufen wird. Jetzt muß er sich aber bei meiner Klasse drum kümmern, was ziemlich oft Fehler geben wird deswegen.

    MfG



  • Wie funktioniert das mit using?

    Benutz Google.

    Generell ist das ja aber ein Problem, da C# Programmierer sich ja im normalfall nicht um den Destrukto kümmern, da der ja automatisch gerufen wird. Jetzt muß er sich aber bei meiner Klasse drum kümmern, was ziemlich oft Fehler geben wird deswegen.

    Falsch. Im Normalfall muss der C# Programmierer dafür sorgen dass Dispose() aufgerufen wird, wenn IDisposable implementiert ist. Dur wirst dich wundern, wieviel mal Du hättest Dispose() aufrufen müssen, es aber nicht getan hast, weil Du es nicht gewusst hast.

    In der MSDN steht mehr dazu.

    Simon



  • also ist es in C# auch generell so wenn ich ein Objekt mit new instanziiere, dann muß ich auch ein Dispose auf dieses Objekt machen?

    MfG



  • Destiniy schrieb:

    also ist es in C# auch generell so wenn ich ein Objekt mit new instanziiere, dann muß ich auch ein Dispose auf dieses Objekt machen?

    MfG

    Nein.

    Wenn Du in C# ein Object instanziierst das IDispose implementiert hat dann solltest Du auch Dispose aufrufen.

    An der Stelle wäre es dringend geraten Dir mal die Grundlagen der GC anzulesen...



  • Nicht nur Grundlagen über den GC, über alles...



  • Und bitte hört auf Finalizer bzw. Dispose-Funktionen als Destruktor zu bezeichnen.

    Finalizer, Dispose und Destruktor sind drei ziemlich unterschiedliche Dinge.



  • Hier noch Links zu den besagten drei Themen:
    http://msdn.microsoft.com/en-us/library/498928w2.aspx
    http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
    http://msdn.microsoft.com/en-us/library/ms177197.aspx
    http://www.codeproject.com/KB/mcpp/cppclidtors.aspx

    Und eine Zusammenstellung der etwas verwirrenden Ausdrücken und Syntax:

    IDisposable
    C++/CLI: ~ClassName() bewirkt via Kompiler ein automatisches Implementieren der IDisposable Schnittstelle mit der Dispose() Methode.
    (Ein explizites Ableiten von IDisposable führt zu einem Kompilier- Fehler.)

    C#: Das äquivalente in C# ist es die IDisposable Schnittstelle zu implementieren.

    Finalizer
    C++/CLI: !ClassName() bewirkt via Kompiler, dass die Finalize() Methode überschrieben wird.

    C#: ~ClassName() bewirkt via Kompiler, dass die Finalize() Methode überschrieben wird.
    (Ein explizites überschreiben von Finalize() führt zu einem Kompilier- Fehler.)

    Unglücklicherweise wird sowohl in C# als auch in C++/CLI bei ~ClassName() oft von Destruktor gesprochen, obwohl das Verhalten nicht den Destruktoren von ISO C++ entspricht.

    Simon



  • Unglücklicherweise wird sowohl in C# als auch in C++/CLI bei ~ClassName() oft von Destruktor gesprochen, obwohl das Verhalten nicht den Destruktoren von ISO C++ entspricht.

    Jopp. Und noch unglücklicher finde ich den Umstand, dass C# und C++ unter ~ClassName() was unterschiedliches verstehen 👎
    (wie ja auch aus deinem Beitrag hervorgeht)
    Verwirrte Anfänger sind da vorprogrammiert.

    (Und es ist auch für erfahrene Programmierer nicht angenehm, kann man schonmal drüber stolpern.)

    Umso wichtiger finde ich es immer den richtigen Ausdruck zu verwenden, wenn man irgendwo was diskutiert, was mit Dispose-Funktionen, Finalizern und/oder Destruktoren zu tun hat.



  • erstmal danke für die Links.

    ich habe jetzt in meinem C++/ClI Code den finalizer implementiert, dadurch ruft der GC den dann auch automatisch.



  • Destiniy schrieb:

    erstmal danke für die Links.

    ich habe jetzt in meinem C++/ClI Code den finalizer implementiert, dadurch ruft der GC den dann auch automatisch.

    Dispose solltest Du dennoch aufrufen.



  • theta schrieb:

    Dispose solltest Du dennoch aufrufen.

    Nein, brauchst Du nicht zu machen....

    http://stackoverflow.com/questions/867114/why-no-reference-counting-garbage-collection-in-c

    Lies Dir das mal bitte bis zum Ende genau durch.



  • davon bin ich auch ausgegangen, da der GC ja genau die Funktion hat



  • Fred F. schrieb:

    theta schrieb:

    Dispose solltest Du dennoch aufrufen.

    Nein, brauchst Du nicht zu machen....

    http://stackoverflow.com/questions/867114/why-no-reference-counting-garbage-collection-in-c

    Lies Dir das mal bitte bis zum Ende genau durch.

    Widerspruch.

    Wenn es ein explizites Dispose gibt sollte man das aufrufen. Der Sinn des Dispose liegt gerade darin unmanaged und/oder begrenzte Resourcen wieder freizugeben sobald man sie nicht mehr braucht. Da man nicht weis wann, genaugenommen ncihtmal _ob_ die GC ein Object aufräumt können so wichtige Resourcen wie z.B. files blokiert durch die GC blokiert werden.

    Was man _nicht_ braucht ist für jede Klasse IDisposeable zu implementieren, sondern nur für solche KLassen, bei denen eben jene unmanaged und/oder begrenzten Resourcen benutzt werden.

    On a sidenode.

    Der oben gelinkte Artikel ist sehr ungenau. Dispose ist kein Ersatz für den Destructor so wie es da eingangs dargestellt wird, sondern ein Pattern um ein Problem der GC zu lösen.



  • Genau.
    Das Problem ist ja nicht der Speicher des Objekts welches IDisposable implementiert. Das Problem sind die "unmanaged" Resourcen wie File-Handles, Datenbank-Connections, Fenster-Handles etc.
    Wenn du nicht Dispose aufrufst, dann werden diese Dinge eben erst irgendwann mal freigegeben.

    Bei Files kann das dann z.B. dazu führen, dass du irgendwelche Files nicht aus anderen Programmen öffnen/umbenennen/schreiben/löschen kannst, nur weil du irgendwann mal von Programm X aus auf dieses File zugegriffen hattest, und Programm X noch läuft.

    Bei Datenbank-Connections/Recordsets/... kann es dazu führen dass die Performance des Datenbank-Server in die Knie geht, weil der auf einmal tausende Connections sieht -- auch wenn dein Programm bloss immer eine verwendet.

    Und bei anderen Resourcen kann es schlicht und einfach sein, dass sie "ausgehen". Es gibt z.B. nur endlich viele Window-Handles. Wenn ein Programm zu viele Window-Handles "ansammelt" (weil es seine Fenster nicht sauber disposed), kann es sein, dass irgendwann mal irgendwo einfach Buttons/Texte/... oder gar ganze Fenster "fehlen", weil das System keine Handles mehr frei hat.



  • Man sollte eben Wissen warum man wie welche Funktion nutzt.
    Ein paar PEN oder SolidBrush ohne Dispose und schon kann man Probleme haben.


Anmelden zum Antworten