IDisposable 基类拥有托管一次性资源,在子类中做什么?
我有一个基类,它拥有托管一次性资源(.NET PerformanceCounter)。 我了解如何在类上实现 IDisposable,以便我可以在资源上显式调用 Dispose。 从我看到的例子来看,人们通常使用私有布尔成员变量“dispose”,并在 Dispose 中将其设置为 true。 稍后,如果尝试访问公共方法或属性,则在“dispose”为 true 的情况下会引发 ObjectDisposeException。
那么在子类中呢? 子类如何在其公共方法和属性中知道它们已被释放? 起初我认为子类不必有任何特殊的东西(比如实现它们自己的 Dispose 版本),因为需要处理的东西仅在基类中(让我们假设子类不会添加任何需要处理的数据)需要显式处置)并且基类的 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 。
您会
IWritableCounter wc = new WritableWidgetCounter();
wc.Increment();
wc.Dispose();
wc.Increment();
wc = null;
看到基类拥有并管理 PerformanceCounter 对象(这是一次性的 重写 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
}
简单地设置一个 ReadableCounter/WritableCounter 级别的“已处置”成员变量?
如果将基类(BaseCounter)声明为受保护(或使其成为受保护属性)怎么样? 这样,子类就可以引用它,而不是仅仅为了记住 Dispose 已经发生而添加 Dispose 方法。
我错过了这艘船吗?
I have a base class that owns a managed disposable resource (.NET PerformanceCounter). I understand about implementing IDisposable on the class so that I can explicitly call Dispose on the resource. From the examples I have seen, people typically use a private boolean member variable "disposed" and set it to true inside of Dispose. Later, if there is an attempt to access a public method or property, an ObjectDisposedException is raised if "disposed" is true.
What about in the subclasses? How would the subclasses, in their public methods and properties, know that that they had been disposed? At first I thought that the subclasses would not have to anything special (like implement their own version of Dispose) since the thing that needs to be disposed is only in the base class (let's assume that the subclasses won't be adding any data that needs to be explicitly disposed) and the base class' Dispose should handle that. Should the subclasses override the base class' virtual Dispose method solely for the purpose of setting its own "disposed" member variable?
Here is a very stripped-down version of the class hierarchy in question.
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
}
In our system, ReadableCounter and WritableCounter are the only subclasses of BaseCounter and they are only subclassed to one more level via a code generation processes. The additional subclassing level only addes a specific name so that it becomes possible to create objects that correspond directly to named counters (e.g. if there is a counter that is used to count the number of widgets produced, it ends up being encapsulated in a WidgetCounter class. WidgetCounter contains the knowledge (really, just the counter name as a string) to allow the "WidgetCounter" performance counter to be created.
Only the code-generated classes are used directly by developers, so we would have something like this:
class WritableWidgetCounter : WritableCounter
{
public WritableWidgetCounter
: base ("WidgetCounter")
{
}
}
class ReadableWidgetCounter : ReadableCounter
{
public ReadableWidgetCounter
: base ("WidgetCounter")
{
}
}
So, you see that the base class owns and manages the PerformanceCounter object (which is disposable) while the subclasses use the PerformanceCounter.
If I have code like this:
IWritableCounter wc = new WritableWidgetCounter();
wc.Increment();
wc.Dispose();
wc.Increment();
wc = null;
How could WritableCounter know, in Increment, that it had been disposed? Should ReadableCoutner and WritableCounter simply override the BaseCounter's
protected virtual void Dispose(bool disposing)
something like this:
protected virtual void Dispose(bool disposing)
{
disposed = true; //Nothing to dispose, simply remember being disposed
base.Dispose(disposing); //delegate to base
}
simply to set a ReadableCounter/WritableCounter-level "disposed" member variable?
How about if the base class (BaseCounter) declared disposed as protected (or made it a protected property)? That way, the subclasses could refer to it rather than adding a Dispose method simply for the purpose of remembering that Dispose had happened.
Am I missing the boat on this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我见过一些具有公共 IsDispose 属性的一次性类。 您可以这样做并在您的子类中检查它。
我所做的另一件事是所有子类方法都调用(并且可以覆盖)的通用受保护“验证”方法。 如果它返回,则一切正常,否则可能会抛出异常。 这将使您的子类与一次性内部结构完全隔离。
I have seen some disposable classes with a public IsDisposed property. You could do that and check it in your sub-classes.
Another thing I've done is a generic protected 'Validate' method that all sub-class methods call (and could override). If it returns, all is well, otherwise it might throw. That would insulate your sub-classes from the disposable innards altogether.
我有用于在基类和子类中实现 IDisposable 的片段。 您可能想要子类的那个。
我想,大部分代码都是我从 MSDN 上获取的。
这是基类 IDisposable 的代码(不是您想要的代码):
这是我在子类中使用的代码(这是您想要的代码):
查找
TODO:
标记。I have snippets that I use for implementing IDisposable, both in the base class and in the subclasses. You'd probably want the one for the subclass.
I swiped most of this code from MSDN, I think.
Here's the code for the base class IDisposable (not the one you want):
And here's the code I use in the subclasses (this is the code you want):
Look for the
TODO:
marks.