У меня есть приложение Visual Studio 2008 C # .NET 2.0CF. Я использую компонентную базу, из которой получены два конкретных компонента. Приложение сначала пытается использовать SomeDisposableComponent
. Его конструктор выдает исключение, потому что он требует недоступной функции. Затем приложение пытается SomeOtherDisposableComponent
. Строительство успешно завершено.
Проблема в том, что конструктор первого компонента уже добавил себя в контейнер компонентов формы до того, как было сгенерировано исключение. Таким образом, когда форма удаляется, вызывается элемент Dispose()
первого компонента, даже если объект никогда не создавался полностью. Это вызывает проблемы для деструктора второго компонента.
Как я могу гарантировать, что когда первый компонент генерирует исключение в конструкции, ссылки на него удаляются?
public abstract class SomeDisposableComponentBase : Component
{
private System.ComponentModel.IContainer components;
private SomeInternalDisposable s_ = new SomeInternalDisposable();
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_;
protected override void Dispose(bool disposing)
{
// called twice. the first time for the component that failed to initialize properly.
// the second for the one that was used.
if (!disposed_)
{
if (disposing && (components != null))
{
components.Dispose();
}
// on the second call, this throws an exception because it is already disposed.
s_.Close();
disposed_ = true;
}
base.Dispose(disposing);
}
#endregion
}
public SomeDisposableComponent : SomeDisposableComponentBase
{
public SomeDisposableComponent() : base()
{
}
public SomeDisposableComponent(IContainer container) : base(container)
{
// This will throw an exception if it requires a feature that isn't available.
SomeInitFunction();
}
protected override void Foo()
{
// Do something...
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
public partial class my_form : Form
{
private SomeDisposableComponentBase d_;
public my_form()
{
InitializeComponent();
if (null == components)
components = new System.ComponentModel.Container();
try
{
// try the default component
d_ = new SomeDisposableComponent(components);
}
catch (System.Exception)
{
try
{
// the default component requires some feature that isn't available. Try a
// backup component.
d_ = new SomeOtherDisposableComponent(components);
}
catch (System.Exception e)
{
// display error to the user if no suitable component can be found.
}
}
}
/// 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);
}
}
Спасибо,
PaulH
Редактировать: Удален неиспользуемый код
Контейнер внутри SomeDisposableComponentBase
сбивал с толку. Это не относится к проблеме, и я должен был удалить ее раньше.
public abstract class SomeDisposableComponentBase : Component
{
private SomeInternalDisposable s_ = new SomeInternalDisposable();
protected SomeDisposableComponentBase()
{
}
protected SomeDisposableComponentBase(IContainer container)
{
container.Add(this);
}
protected abstract void Foo();
#region IDisposable Members
bool disposed_;
protected override void Dispose(bool disposing)
{
// called twice. the first time for the component that failed to initialize properly.
// the second for the one that was used.
if (!disposed_)
{
if (disposing)
{
// on the second call, this throws an exception because it is already disposed.
s_.Close();
}
disposed_ = true;
}
base.Dispose(disposing);
}
#endregion
}
public SomeDisposableComponent : SomeDisposableComponentBase
{
public SomeDisposableComponent() : base()
{
}
public SomeDisposableComponent(IContainer container) : base(container)
{
// This will throw an exception if it requires a feature that isn't available.
SomeInitFunction();
}
protected override void Foo()
{
// Do something...
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
public partial class my_form : Form
{
private SomeDisposableComponentBase d_;
public my_form()
{
InitializeComponent();
if (null == components)
components = new System.ComponentModel.Container();
try
{
// try the default component
d_ = new SomeDisposableComponent(components);
}
catch (System.Exception)
{
try
{
// the default component requires some feature that isn't available. Try a
// backup component.
d_ = new SomeOtherDisposableComponent(components);
}
catch (System.Exception e)
{
// display error to the user if no suitable component can be found.
}
}
}
/// 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);
}
}