Извлечение из компонента и правильная реализация IDisposable - PullRequest
3 голосов
/ 20 мая 2010

У меня есть проект Visual Studio 2008 C # .NET 2.0 CF с абстрактным классом, производным от Component. Из этого класса я извлекаю несколько конкретных классов (как в моем примере ниже). Но когда я выхожу из своей формы, хотя вызывается член Dispose () формы и вызывается компоненты.Dispose (), мои компоненты никогда не удаляются.

Кто-нибудь может подсказать, как я могу исправить этот дизайн?

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);
    }
}

* Хочу заметить, что FX-Cop дает мне подсказку. Но, если я пытаюсь объявить эту функцию запечатанной, я получаю ошибку:

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

Объявление этой функции приводит к переопределению:

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

Спасибо, PaulH

Ответы [ 2 ]

7 голосов
/ 20 мая 2010

SomeDisposableComponentBase следует переопределить Component.Dispose(Boolean).

Вам также необходимо удалить метод SomeDisposableComponentBase.Dispose() (который не принимает аргументов), , потому что он скрывает реализацию Component.Dispose , поэтому они рассматриваются как разные методы, в зависимости от того, как вы объявляете переменные:

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 голосов
/ 20 мая 2010

Происходит следующее: компилятор интерпретирует метод Dispose для SomeDisposableComponentBase как

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

, который не является переопределением, он дает новую семантику существующему имени внутри вашей иерархии классов. Итак, на самом деле вы создаете новый метод Dispose, который отличается от Component.Dispose.

Проверка Реализация финализации и утилизации для очистки неуправляемых ресурсов статья с официальным руководством о том, как реализовать метод IDisposable.Dispose.

...