IsDisposed assertions



  • Gibt es irgendein Feature im .NET Framework welches man einschalten kann um rauszubekommen ob ein Programm auch alles brav disposed was disposed gehört?
    Bei eigenen Klassen ist das ja relativ einfach zu realisieren, einfach ein ASSERT(this.IsDisposed) (sinngemäss) in den Finalizer packen.

    Kann man auch schön in Klassen machen die garkeinen Finalizer brauchen, dann klammert man den ganzen Finalizer eben in #ifdef _DEBUG damit der im Release-Build nicht unnötig Performance frisst.

    Aber zurück zu meiner Frage. Gibt's irgendeine Möglichkeit sowas auch für fertige .NET Framework Klassen zu bekommen? Oder vielleicht irgendwelche Tools die das anzeigen können? (Können Memory-Profiler sowas?)



  • Du bist hier bei c# und NET. So wie das aussieht möchtest du aber c++ NET.



  • Unix-Tom schrieb:

    Du bist hier bei c# und NET. So wie das aussieht möchtest du aber c++ NET.

    Wie kommst Du da drauf?
    Simon

    Edit: Ok, das #ifdef ist nicht ganz koscher, jedoch gibts prinzipiell conditional compilation mit #if ... #endif.
    Edit2: Ok, auch das ASSERT(..) ist nicht ganz koscher... :-))



  • Meine Frage bezieht sich auf .NET, egal in welcher Sprache.
    Konkret mache ich mehr C++/CLI als C#, aber das sollte bei dieser Frage denke ich keine Rolle spielen.

    Was conditional-compilation und ASSERTs angeht, darüber mag jeder denken was er mag, das war ja mehr nebenbei erwähnt.

    Also nochmal konkret: was gibt's bei .NET für Hilfsmittel (Tools, Framework Funktionen etc.) mit denen man Stellen finden kann wo Objekte nicht disposed werden.

    Solche Fehler passieren schnell, und ohne weitere Hilfsmittel sind die recht schwer zu finden - den Code Klasse für Klasse, Zeile für Zeile durchzugehen ist halt nicht gerade lustig, und auch nicht sehr effizient.

    Ich denke da an Funktionen wie z.B. den Debug-Heap bei MSVC, oder Tools wie Bounds-Checker (nur nach möglichkeit gratis oder zumindest billig). Da die .NET Plattform ja nicht gerade unbeliebt ist, und da es genügend Programmierer gibt die ... sagen wir mal einfach nicht alle Regeln zum Thema "Dispose" kennen (einfaches Beispiel: Form.Show -> Dispose automatisch, Form.ShowDialog -> Dispose muss manuell aufgerufen werden) denke ich mir muss es doch da einige nette Debugging-Tools geben.



  • Vielleicht hilft Dir die SOS.dll weiter.
    http://msdn.microsoft.com/en-us/library/bb190764(VS.80).aspx

    Hier gibts noch ein MSDN Magazin Artikel:
    http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

    Simon

    Edit:
    Vielleicht reichen Dir die Informationen, die mit Perfmon.exe rauszukriegen sind. Bei Performance Object ".NET Memory" gibts einige interessante Counters.



  • Hallo

    hustbaer schrieb:

    (einfaches Beispiel: Form.Show -> Dispose automatisch, Form.ShowDialog -> Dispose muss manuell aufgerufen werden) denke ich mir muss es doch da einige nette Debugging-Tools geben.

    Echt? Das wusste ich noch nicht.

    chrische



  • Ein Memory-Profiler bietet das normalerweise an, das .Net Framework stellt also derartige Mechanismen schon bereit. Ich würde aber tatsächlich lieber nen fertigen Profiler verwenden und nicht von Hand was dafür coden.

    EDIT: Genaugenommen gehen die Profiler auf die Finalizer-Queue los, aber eine korrekt geschrieben Dispose() Methode entfernt die Objekte eben aus dieser Queue. Also du musst nach finalized Objekten schauen.



  • Huch, hab ganz übersehen dass hier Antworten drin sind 🙂

    Danke für die Hinweise.

    Was Performance-Counter angeht: Counter alleine sind ja nicht besonders aussagekräftig. Man weiss dann zwar wieviel "schief geht", aber nicht genau wo.

    Kennt jemand einen guten Profiler/Memory-Profiler für .NET? Gratis bzw. billig? 🙂



  • chrische5 schrieb:

    Hallo

    hustbaer schrieb:

    (einfaches Beispiel: Form.Show -> Dispose automatisch, Form.ShowDialog -> Dispose muss manuell aufgerufen werden) denke ich mir muss es doch da einige nette Debugging-Tools geben.

    Echt? Das wusste ich noch nicht.

    chrische

    Jo, echt 🙂
    Der Sinn dahinter ist denke ich folgender:

    private void Foo()
    {
        using (SettingsDialog sd = new SettingsDialog(this.settingA, this.settingB))
        {
            sd.ShowDialog(this); // wenn hier automatisch b.Dispose gemacht würde
            this.settingA = sd.GetSettingA(); // hätten wir hier
            this.settingB = sd.GetSettingB(); // und hier ein Problem, da wir auf einen Zombie zugreifen müssten
        }
    }
    

    Natürlich könnte man (oft, aber nicht immer) "GetSettingA" und "GetSettingB" so implementieren dass sie auch auf einem Zombie (=Objekt auf das bereits Dispose aufgerufen wurde) noch funktionieren, aber es ist einfach nicht sauber. Sauber wäre wenn "GetSettingA" und "GetSettingB" in dem Fall eine ObjectDisposedException werfen, und damit würde der Code oben nichtmehr funktionieren wenn ShowDialog die Form selbst disposen würde. Und eben, in manchen Fällen ginge das nichtmal gescheit - z.B. wenn man nach ShowDialog noch auf irgendwelche Dinge in der Form zugreifen muss welche selbst disposable sind.

    Bei Form.Show wäre es dagegen ganz schrecklich doof wenn man Dispose selbst aufrufen müsste - dann müsste man immer tracken welche Forms man anzeigt, bzw. in jeder Form das "this.Dispose" in OnClose (oder wie die Funktion heisst) selbst aufrufen. Was beides IMO ziemlich grausam wäre.

    Von daher eigentlich "logisch" dass es sich so und nicht anders verhält, aber man kann schnell drüberstolpern wenn man es nicht weiss bzw. einfach nicht drüber nachgedacht hat.



  • @hustbaer
    Was konntest Du jetzt unternehmen, um die Dispose Aufrufe zu verfolgen?

    Simon



  • Hallo

    Wenn ich also ohne using arbeite und ShowDialog aufrufe, muss ich noch sd.Dispose() aufrufen?

    chrische



  • chrische5 schrieb:

    Hallo

    Wenn ich also ohne using arbeite und ShowDialog aufrufe, muss ich noch sd.Dispose() aufrufen?

    chrische

    Ja.



  • theta schrieb:

    @hustbaer
    Was konntest Du jetzt unternehmen, um die Dispose Aufrufe zu verfolgen?

    Simon

    Noch nix 🙂
    Im Moment ist das nicht das Dringendste, deswegen hab' ich da (noch) nicht viel Zeit investiert. Ich wollte hauptsächlich vorab fragen ob jmd. da gute Tools kennt. Dachte mir dass viele Leute da was gutes Kennen - wohl falsch gedacht 🙂

    Was mir heute noch eingefallen ist...:

    In .NET gibt's ja einiges an Reflection, und dynamisch Code generieren kann man ja auch. Leider hab' ich mich mit diesen Dingen noch nicht soweit auseinandergesetzt dass ich weiss was geht und was nicht. Daher die Frage: Könnte ein Programm (z.B. so ein "Memory-Profiler") hergehen und sich alle Stellen in einem Programm raussuchen wo ein ctor einer Klasse aufgerufen wird die von IDisposable erbt, und dann dort dynamisch Code einfügen der für jedes Objekt mitschreibt wo (Stacktrace) der Aufruf stattgefunden hat der das Objekt initialisiert hat? Bzw. den entsprechenden Code gleich in den ctor einfügen? Das wäre dann so ziemlich das Beste was ich mir diesbezüglich vorstellen kann - dann könnte man zu den finalisierten Objekten auch immer gleich sehen wo diese angelegt wurden.

    Im Prinzip ähnlich zu dem was der gute alte Bounds-Checker macht wenn man den generierten Code von Bounds-Checker vor einem Testlauf verwursten lässt.

    Interessieren würde mich a) ob das grundsätzlich möglich ist und b) ob jemand eine fertige Implementierung kennt.



  • .Dispose() nervt unheimlich - Ich frag mich ob das nich irgendwie möglich gewesen wäre das es auch ohne klappt 😉


Anmelden zum Antworten