Dispose bei von .NET abgeleiteten Klassen



  • Ich habe meine Klasse MyUC von UserControl abgeleitet.
    Dabei hat der Designer automatisch eine Datei namens "MyUC.Designer.cs" erstellt.
    Die Klasse kapselt außerdem Daten einer externen COM Componente die nach Verwendung dringend wieder frei gegeben werden müssen.

    Jetzt sollte ich nach meinem aktuellen Kenntnisstand in meiner Klasse MyUC eine Dispose() Methode implementieren, in der ich dann die externe Kommunikation über die COM Komponente wieder trenne.

    In meinem Hauptprogramm muss ich dann nach Beendigung meiner Kommunikation die Dispose() Methode des von MyUI instanziierten Objekts aufrufen.

    Jetzt habe ich aber das Problem, dass ich die Dispose Methode der MyUC Klasse gar nicht überschreiben kann, weil dies bereits im Designer "MyUC.Designer.cs" gemacht wird.

    Wo packe ich denn jetzt meine Anweisungen zum trennen der COM Komponente rein??



  • Hallo,

    ich weiß, das ist ziemlich unelegant von MS gemacht (wie viele andere Dinge auch 😉
    Aber du kannst einfach die Dispose-Methode dort löschen und in deine eigene C#-Datei neu erstellen (nur die InitializeComponent sollte man auf keinen Fall abändern, da diese bei Bedarf vom Designer überschrieben wird).



  • Ich muss zugeben, mir ist nicht so ganz wohl beim Editieren in der "Designer" Datei.

    Ich denke ich werde jetzt einfach eine Close() Methode anlegen und darin am Ende this.Dispose() aufrufen...

    Deine Aussage hat mir aber schon geholfen. Jetzt weiß ich, dass ich nicht nur zu blöd bin. Vielmehr scheint es einfach unschön zu sein ein Dispose in einer von einem Steuerelement abgeleiteten Klasse zu implementieren.



  • @Marco82
    Jede vom Wizard erzeugte Form (und soweit ich weiss auch jedes UserControl) bekommt eine "components collection" verpasst.

    private System.ComponentModel.IContainer components = null;
    

    Diese wird dann in der Default-Implementierung brav disposed.
    Da kannst du Dinge reinstecken die IComponent implementieren, und die werden dann entsprechend mit entsorgt.
    Wenn du einen Wrapper um das COM Interface hast, dann implementiere in diesem Wrapper einfach IComponent , steck das Wrapper Objekt in components rein, und fertig.

    Wenn nicht, dann kann man sich mit einer einfachen Hilfsklasse behelfen, die selbst IComponent implementiert, und den Dispose-Call einfach als Event rausreicht.
    Diese Hilfsklasse steckt man dann in components rein, hängt sich auf den Event, und fertig.

    Sonst gibt es noch den Closed Event und die OnClose Methode die man überschreiben kann. Sollte auch vollkommen ausreichend sein, denn ich sehe jetzt keinen Grund warum eine Form jemals direkt disposed werden sollte.

    In meinem Hauptprogramm muss ich dann nach Beendigung meiner Kommunikation die Dispose() Methode des von MyUI instanziierten Objekts aufrufen.

    Nö. Du sollst bloss die Form irgendwie zumachen. Entweder die Form schliesst sich selbst, oder sie wird halt von aussen geschlossen. Wie auch immer, irgendwie wird Close aufgerufen. Und Close ruft dann Dispose auf. Kein Grund das von Hand zu machen.



  • Klingt plausibel.

    Aber eins habe ich noch nicht ganz verstanden.
    Die vom Designer generierte Dispose() Methode gibt den Dispose nur an components weiter, wenn der Parameter bool disposing == true.
    Das heißt ja implizit, dass nur "Managed" Objekte in den components container einsortiert werden sollten.

    /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
          if (disposing && (components != null))
          {
            components.Dispose();
          }
          base.Dispose(disposing);
        }
    

    Wie werden die COM Objekte in .NET gehandelt. Ich meine, das COM Objekt ist definitiv "Unmanaged", aber in .NET spreche ich es ja nicht direkt, sondern über die Interop Services an. Und die sind wieder "Managed".

    Ich verwende ein UserControl welches das COM Objekt beinhaltet. Bei jedem Verbindungsaufbau wird das UserControl neu instanziiert und bei jedem Verbindungsabbau / abbruch zerstört.
    (Das brauche ich so, weil ich erst beim Verbindungsaufbau abhängig vom Typ der Gegenstelle die sich meldet weiß, welche COM Komponente ich brauche. Die verschiedenen COM Komponenten haben z.T. völlig unterschiedliche Funktionalitäten und sind deshalb auch in verschiedene UserControls gekapselt.)

    Jetzt muss ich sicherstellen, dass das COM Objekt beim Zerstören meines UserControls sicher mit Zerstört wird.
    (Sonst geht der nächste Verbindungsaufbau schief)

    Nach meinem aktuellen Kenntnisstand (danke hustbear) ist die eleganteste Lösung das in der Dispose() Methode meines UserControl zu tun. Bei Aufruf dieser Methode (egal ob explizit oder implizit) kann ich dann sicher sein, dass mein COM wirklich zerstört wurde.



  • hustbaer schrieb:

    @Marco82
    Wenn du einen Wrapper um das COM Interface hast, dann implementiere in diesem Wrapper einfach IComponent , steck das Wrapper Objekt in components rein, und fertig.

    Einen zusätzlichen Wrapper (zu dem den .NET ohnehin schon für COM Objekte erzeugt) kann ich leider nicht erstellen, weil sonst die GetInterface() Methode der "Hauptschnittstelle" des COM Objekts nicht mehr funktioniert.
    Wobei meines Wissens die GetInterface() Methode (der von .NET durch Interop gekapselten COM Komponente) in etwa dem IDispatch des COM-Server an sich entspricht.

    COM_Komponend_3rdParty.Machine objMachine = new COM_Komponend_3rdParty.Machine();
    MyNamespace.MyCOMWrapper objVersion;
    
    objVersion = (MyNamespace.MyCOMWrapper)objMachine.GetInterface(COM_Komponend_3rdParty.DNC_INTERFACE_OBJECT.DNC_INTERFACE_VERSION);
    

    Exception:
    Der System.__ComObject-Typ kann nicht in MyNamespace.MyCOMWrapper konvertiert werden.


Anmelden zum Antworten