What is the simplest IDisposable pattern in c#?
如果我有一个只使用托管资源的类,那么我认为不需要完全实现IDisposable模式。
这当然足够了:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ManagedResourceClient : IDisposable
{
private ITheManagedResource _myManagedResource = new TheManagedResource ()
public void Dispose ()
{
if ( _myManagedResource != null )
{
_myManagedResource .Dispose();
_myManagedResource = null;
}
}
} |
我看不出使用的理由:
- 终结器,因为它只使用实现IDisposable的托管资源
- "disposing"标志,因为这是由空检查处理的
- 虚拟处理方法,因为不需要区分GC调用和直接调用。
以上内容是否正确?
- 这个应用程序是多线程的吗?
- "我有一个仅使用托管资源的类",那么您可能不需要Dispose
- @Steve一点也不正确,正如在示例代码中所看到的那样,对象引用其他托管的可释放对象。对于世界上几乎每一个C程序员来说,这是他们唯一需要编写的IDisposable类。
- @servy:voila,下一个毫无理由地实现IDisposable的对象
- @为其他对象引用命名为managedResource。我假设一个也不需要处理
- @史蒂夫考虑到他打电话给Dispose,显然情况并非如此。
- @Timschmelter你有什么依据支持这个观点?可能它包装了一个未映射的资源,也可能它包装了另一个本身具有非托管资源的托管资源。
- 假设有一个类是从ManagedResourceClient派生的,它使用许多非托管资源。您再次实现IDisposable!!这里使用虚拟释放(bool)方法
- @他似乎认为每个类都需要实现IDisposable。
- op您需要指出您是否在使用非托管资源。如果整个应用程序只使用托管资源,那么不,您不需要它。
- @我想是蒂姆施梅勒!!
- @蒂姆施梅勒,你这么说的依据是什么?他正在询问如何为一个类正确地实现IDisposable,该类具有本身为IDisposable的字段。他没有说,也没有指出,每门课都应该是一次性的。
- @服务生:我的基础就是他所展示的。他甚至使用了TheManagedResource这个名称,它清楚地表明它只包含管理资源。但它仍然实现了IDisposable。按照这种模式,难怪他也需要在这里实现它。但问题不是如何,而是为什么。如果TheManagedResource不实现它,就不需要在这里实现它。
- @timschmelter所以你认为用一个字段作为实现IDisposable的托管对象的类永远不合适?例如,您从来没有用Stream作为字段编写过类,即使Stream是实现IDisposable的托管资源?说它是托管资源仅仅意味着它本身是围绕非托管资源的托管包装器,而不是实际的非托管资源本身,这当然与问题有关;如果字段实际上是不安全的文件指针,那么他就无法编写此代码。
- @很抱歉,我们会澄清这个例子。所讨论的托管资源仍可以IDisposable,否则Dispose()调用将无法编译。
- @servy:流是托管资源?来自msdn:"…Dispose还释放操作系统资源,如用于任何内部缓冲的文件句柄、网络连接或内存。……"
- @Timschmelter是的,Stream是一种管理资源。它组成非托管资源。类的全部目的是围绕非托管资源作为托管包装,这样类的使用者实际上不需要关心非托管资源的详细信息,而是可以完全处理托管资源。
- @Marshalltigerus不,这不是多线程的。我猜这会改变事情,但我想让这个例子尽可能简单。
- 史蒂芬·克利里(Stepen Cleary)为这个话题写了一篇文章:"IDisposable:你妈妈从未告诉过你的关于资源分配的事情。"
- @我从您的注释中了解到,如果您将流用作类中的字段或属性,那么这个类不实现idsposable?
- @我说的完全相反。
- @服务生。对不起,我弄错了!所以我们现在在同一队
- 有一种理论认为,sqlcommand对象是不需要处理的对象,因此不应该被处理——这是我个人不认同的一种理论。
- @Cato SqlCommand可处置的唯一原因是它继承了Component和Component是可处置的。它在Dispose方法中实际执行的唯一操作是将表示元数据缓存的私有变量设置为空。这就像江户一〔3〕一样,是一次性的阶级,但从来没有人处理过。
您几乎拥有它,因为您的类不是密封的,所以有人可以从您的类派生,并且派生类也可能需要释放一个对象。使类密封,并且当前的实现是良好的。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public sealed class ManagedResourceClient : IDisposable
{
private ITheManagedResource _myManagedResource = new TheManagedResource ()
public void Dispose ()
{
if ( _myManagedResource != null )
{
_myManagedResource .Dispose();
_myManagedResource = null;
}
}
} |
如果你想了解更多关于处理(以及为什么微软给出的带有限定符的股票例子实际上是一个坏例子)的信息,请参阅Stepen Cleary的这篇非常好的文章:"IDisposable:什么是你妈妈从来没有告诉过你的关于资源分配的。"
- 好的,谢谢,如果没有密封,我该怎么办?
- @用户183872将Dispose设为虚拟的或设为受保护的Dispose函数,并将其设为虚拟的(使受保护的函数之一成为"标准"Dispose模式)
- 你也应该确保阅读这篇文章,基本上它会解释为什么你不需要在你的类中有一个限定符,除非你的类是从SafeHandle派生的。将逻辑分为两种类型,一种只处理单个非托管对象(类型0),另一种只保存类型0或其他类型1对象(类型1)。
- @斯科特-事实上,处理模式出错了吗?(除.dispose之外,没有被程序员调用)-这篇文章中的内容是真实世界的问题还是理论上的问题?
- @cato您将看到的主要现实情况是,这是一个因素,如果您正在生成许多短期的可弃对象,通过在可弃对象上使用限定符,您的对象将永远无法作为gen 0垃圾收集的一部分进行收集,因为使用限定符会使您在添加到finialz时得到提升。ER队列。当您有许多寿命很短的一次性对象时,这可能会导致明显的性能问题。
- @斯科特钱伯伦那篇文章真是太棒了!谢谢你的参考。