I have a Visual Studio 2008 C# .NET 2.0 CF project with an abstract class derived from Component. From that class, I derive several concrete classes (as in my example below). But, when I go to exit my Form, though the Form's Dispose() member is called and components.Dispose() is called, my components are never disposed.
Can anybody suggest how I can fix this 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);
}
}
*I note that FX-Cop is giving me a hint here. But, if I try to declare that function as sealed, I get the error:
error CS0238: 'SomeDisposableComponentBase.Dispose()' cannot be sealed because it is not an override
Declaring that function an override leads to:
'SomeDisposableComponentBase.Dispose()': cannot override inherited member 'System.ComponentModel.Component.Dispose()' because it is not marked virtual, abstract, or override
Thanks, PaulH
SomeDisposableComponentBase
should override Component.Dispose(Boolean)
.
You also need to delete the SomeDisposableComponentBase.Dispose()
method (that takes no arguments), because it hides the Component.Dispose
implementation, so they're treated as different methods, depending on how you declare your 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
}
What is happening is that the compiler is interpreting the method Dispose on SomeDisposableComponentBase as
new public void Dispose()
{
// never called
Dispose(true);
GC.SuppressFinalize(this);
}
which is not an override, it is giving a new semantics to an existing name inside you class hierarchy. So, actually you are creating a new Dispose method that is not the same as the Component.Dispose.
Check Implementing Finalize and Dispose to Clean Up Unmanaged Resources article for the official guidance on how to implement IDisposable.Dispose method.
精彩评论