2010-05-20 5 views
3

J'ai un projet Visual Studio 2008 C# .NET 2.0 CF avec une classe abstraite dérivée de Component. De cette classe, je dérive plusieurs classes concrètes (comme dans mon exemple ci-dessous). Mais, quand je vais quitter mon formulaire, bien que le membre Dispose() du formulaire soit appelé et que components.Dispose() soit appelé, mes composants ne sont jamais éliminés.Dérivation d'un composant et implémentation correcte d'IDisposable

Quelqu'un peut-il suggérer comment je peux réparer ce design?

public abstract class SomeDisposableComponentBase : Component 
{ 
    private System.ComponentModel.IContainer components; 

    protected SomeDisposableComponentBase() 
    { 
     Initializecomponent(); 
    } 

    protected SomeDisposableComponentBase(IContainer container) 
    { 
     container.Add(this); 
     Initializecomponent(); 
    } 

    private void InitializeComponent() 
    { 
     components = new System.ComponentModel.Container(); 
    } 

    protected abstract void Foo(); 

    #region IDisposable Members 
    bool disposed_; 

    /// Warning 60 CA1063 : Microsoft.Design : Ensure that 'SomeDisposableComponentBase.Dispose()' is declared as public and sealed.* 
    public void Dispose() 
    { 
     // never called 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     // never called 
     if (!disposed_) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      disposed_ = true; 
     } 
     base.Dispose(disposing); 
    } 
    #endregion  
} 

public SomeDisposableComponent : SomeDisposableComponentBase 
{ 
    public SomeDisposableComponent() : base() 
    { 
    } 

    public SomeDisposableComponent(IContainer container) : base(container) 
    { 
    } 

    protected override void Foo() 
    { 
     // Do something... 
    } 

    protected override void Dispose(bool disposing) 
    { 
     // never called 
     base.Dispose(disposing); 
    } 
} 

public partial class my_form : Form 
{ 
    private SomeDisposableComponentBase d_; 

    public my_form() 
    { 
     InitializeComponent(); 
     if (null == components) 
      components = new System.ComponentModel.Container(); 

     d_ = new SomeDisposableComponent(components); 
    } 

    /// exit button clicked 
    private void Exit_Click(object sender, EventArgs e) 
    { 
     this.Close(); 
    } 

    /// from the my_form.designer.cs 
    protected override void Dispose(bool disposing) 
    { 
     if (disposing && (components != null)) 
     { 
      // this function is executed as expected when the form is closed 
      components.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 
} 

* Je constate que FX-Cop me donne un indice ici. Mais, si j'essaie de déclarer cette fonction comme scellé, je reçois l'erreur:

error CS0238: 'SomeDisposableComponentBase.Dispose()' cannot be sealed because it is not an override 

Déclarant que la fonction d'un remplacement conduit à:

'SomeDisposableComponentBase.Dispose()': cannot override inherited member 'System.ComponentModel.Component.Dispose()' because it is not marked virtual, abstract, or override 

Merci, PaulH

Répondre

7

SomeDisposableComponentBase devrait annulerComponent.Dispose(Boolean).

Vous devez également supprimer la méthode SomeDisposableComponentBase.Dispose() (qui ne prend aucun argument), because it hides the Component.Dispose implementation, ils sont donc considérés comme des méthodes différentes, selon la façon dont vous déclarez vos variables:

using (Component component = new SomeDisposableComponent()) { 
    // Calls Component.Dispose upon exiting the using block 
} 

using (SomeDisposableComponentBase component = new SomeDisposableComponent()) { 
    // Calls SomeDisposableComponentBase.Dispose upon existing the using block 
} 
5

Ce qui se passe est que le compilateur interprète la méthode Dispose sur SomeDisposableComponentBase comme

new public void Dispose() 
{ 
    // never called 
    Dispose(true); 
    GC.SuppressFinalize(this); 
} 

qui n'est pas une dérogation, il donne une nouvelle sémantique à un nom existant à l'intérieur vous hiérarchie de classes. Donc, en fait vous créez une nouvelle méthode Dispose qui n'est pas la même que Component.Dispose.

Vérifiez l'article Implementing Finalize and Dispose to Clean Up Unmanaged Resources pour les instructions officielles sur la façon d'implémenter la méthode IDisposable.Dispose.

+0

Vous avez raison, je vais supprimer la dernière partie de ma réponse. Merci. –

+0

J'apprécie ce lien. Je ne l'avais pas vu auparavant et c'est très instructif. Merci. – PaulH

Questions connexes