У меня есть базовый класс, которому принадлежит управляемый одноразовый ресурс (.NET PerformanceCounter). Я понимаю, как реализовать IDisposable в классе, чтобы я мог явно вызвать Dispose для ресурса. Из примеров, которые я видел, люди обычно используют закрытую логическую переменную-член «disposed» и устанавливают для нее значение true в Dispose. Позже, если есть попытка получить доступ к общедоступному методу или свойству, возникает исключение ObjectDisposedException, если «disposed» имеет значение true.
А как насчет подклассов? Как подклассы в своих открытых методах и свойствах узнают, что они были уничтожены? Сначала я подумал, что подклассам не нужно будет ничего особенного (например, реализовывать собственную версию Dispose), поскольку вещь, которую нужно утилизировать, находится только в базовом классе (давайте предположим, что подклассы не будут добавлять какие-либо данные, которые должен быть явно удален), и базовый класс Dispose должен обрабатывать это. Должны ли подклассы переопределять виртуальный метод Dispose базового класса исключительно с целью установки собственной «удаленной» переменной-члена?
Вот очень урезанная версия рассматриваемой иерархии классов.
class BaseCounter : IBaseCounter, IDisposable
{
protected System.Diagnostics.PerformanceCounter pc;
private bool disposed;
public BaseCounter(string name)
{
disposed = false;
pc = CreatePerformanceCounter(name);
}
#region IBaseCounter
public string Name
{
get
{
if (disposed) throw new ObjectDisposedException("object has been disposed");
return pc.CounterName;
}
}
public string InstanceName
{
get
{
if (disposed) throw new ObjectDisposedException("object has been disposed");
return pc.InstanceName;
}
}
#endregion IBaseCounter
#region IDisposable
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
if (pc != null)
{
pc.Dispose();
}
pc = null;
disposed = true;
}
}
}
public void Dispose()
{
Dispose(true);
}
#endregion IDisposable
}
class ReadableCounter : BaseCounter, IReadableCounter //my own interface
{
public ReadableCounter(string name)
: base(name)
{
}
#region IReadableCounter
public Int64 CounterValue()
{
return pc.RawValue;
}
#endregion IReadableCounter
}
class WritableCounter : BaseCounter, IWritableCounter
{
public WritableCounter(string name)
: base(name)
{
}
#region IWritableCounter
public Increment()
{
pc.Increment();
}
#endregion IWritableCounter
}
В нашей системе ReadableCounter и WritableCounter являются единственными подклассами BaseCounter, и они подклассируются только на еще один уровень посредством процессов генерации кода. Дополнительный уровень подклассов добавляет только определенное имя, так что становится возможным создавать объекты, которые непосредственно соответствуют именованным счетчикам (например, если есть счетчик, который используется для подсчета количества произведенных виджетов, он в конечном итоге инкапсулируется в класс WidgetCounter . WidgetCounter содержит сведения (на самом деле, просто имя счетчика в виде строки), позволяющие создавать счетчик производительности "WidgetCounter".
Только разработанные кодом классы используются непосредственно разработчиками, поэтому у нас будет что-то вроде этого:
class WritableWidgetCounter : WritableCounter
{
public WritableWidgetCounter
: base ("WidgetCounter")
{
}
}
class ReadableWidgetCounter : ReadableCounter
{
public ReadableWidgetCounter
: base ("WidgetCounter")
{
}
}
Итак, вы видите, что базовый класс владеет и управляет объектом PerformanceCounter (который является одноразовым), в то время как подклассы используют PerformanceCounter.
Если у меня есть такой код:
IWritableCounter wc = new WritableWidgetCounter();
wc.Increment();
wc.Dispose();
wc.Increment();
wc = null;
Как WritableCounter мог узнать в Приращении, что он был уничтожен? Должны ли ReadableCoutner и WritableCounter просто переопределять BaseCounter
protected virtual void Dispose(bool disposing)
как то так:
protected virtual void Dispose(bool disposing)
{
disposed = true; //Nothing to dispose, simply remember being disposed
base.Dispose(disposing); //delegate to base
}
просто установить переменную члена «disposed» уровня ReadableCounter / WritableCounter-уровня?
Как быть, если базовый класс (BaseCounter) объявлен утилизированным как защищенный (или сделал его защищенным свойством)? Таким образом, подклассы могут ссылаться на него, а не добавлять метод Dispose просто для того, чтобы вспомнить, что произошло удаление.
Я скучаю по лодке на этом?