被处置物体的行为

时间:2013-02-02 06:58:39

标签: c# idisposable

我有一个IDisposable接口的课程。现在我不知道应该实施什么样的行为。在Dispose方法之后,应该为此类中的每个方法调用抛出ObjectDisposedException,还是只应在指定的方法中抛出异常,例如对已处置资源的数据访问?

我测试了Bitmap对象(只是示例):

Bitmap b = new Bitmap (100, 100);
b.Dispose (); // if i remove this line - console will display: Format32bppArgb
Console.WriteLine (b.PixelFormat);
Console.ReadKey ();

控制台显示: DontCare

因此没有抛出异常。在我调用Dispose后,Bitmap对象允许使用PixelFormat属性。我应该遵循这种行为吗?

3 个答案:

答案 0 :(得分:1)

我对这个问题以及许多其他问题的理解是“做有意义的事情”。

在某些情况下,在某个类释放其资源后使用某些类成员可能是非常合理的。实际上,某些情况可能需要这样的使用。例如,如果一个对象通过网络连接管理异步事务,可能会要求它关闭,然后在它完成之后,询问它已处理了多少事务,是否有任何事务处理悬空等等。在关闭完成之后才能知道这些统计数据的值,并且在概念上没有错误地要求对象关闭然后询问它有关已经完成的事情的历史信息。

虽然有人可能认为Close应该关闭连接,同时允许使用报告历史信息的属性,而Dispose应该关闭并禁止使用这些属性,我认为这样区别无益。除其他事项外,人们可能希望连接释放与其相关的所有资源(为了允许“重新打开”请求,Close可能会做的事情可能会避免。此外,如果CloseDispose之间的行为没有其他差异,我认为没有必要纯粹要求两个单独的方法Dispose可以使统计数据无效。< / p>

在某种意义上,许多IDisposable个对象可能被视为具有两个部分 - 一个与外部资源交互的实体,以及一个与托管代码交互并且本身可能具有有限功能的实体。虽然“关注点分离”原则会暗示这两个部分应该是单独的对象(实际上,当这样的拆分可能有帮助时会有尖刺),在许多情况下,客户端代码将希望保留单个引用,为两个目的服务。该引用必须实现IDisposable,但处理不应该破坏托管代码方面。

作为示例,请考虑WinForms Font类。该类封装了两件事:(1)有关字体(字体,大小,样式等)的信息集合,以及(2)GDI字体句柄。当FontDispose d时,它不能再用于绘制文字,但它不会忘记字体,样式等。给定Dispose d字体,它是可能的使用旧信息构造新字体。不幸的是,大多数允许读取此类信息的属性都被Dispose明确地无效,这意味着在许多情况下,如果想要生成类似于现有但已处置的{{}的字体。 1}}但是有一些变化,必须构造一个新的字体,其中包含从旧的字体复制的信息,构建另一个基于该字体的新字体,然后Font创建的第一个新字体。有一个Dispose类可能有助于保存与typestyle等相关的信息,以便在想要保存字体描述但不需要GDI句柄的情况下,字体描述可以存储在非一次性类中,但这不是类的设计方式。

答案 1 :(得分:1)

  

应该只在指定的方法中引发异常,例如对已处置资源的数据访问吗?

这是自动的,一个有终结器的类应该抛出这样的情况。毕竟,该方法将访问一个不再存活的操作系统对象,这将产生错误。最好用一个像ObjectDisposedException这样的清楚的报告来报告,而不是由操作系统错误代码产生的一个神秘的报告。

你给出的Bitmap示例是一个非常悲伤的例子,但对于GDI +类来说并不罕见。它们通常具有非常差的错误处理。让这不是一个例子。

上一段中的关键词是“具有终结者的类”。你的类应该有一个终结器,所以你是否抛弃自己而不是将它留给你封装的一次性类中的方法是值得商榷的。一般来说,你应该避免它,它往往会使你的代码混乱,几乎没有什么好处。但是如果你包装一个像Bitmap那样返回错误数据的糟糕类,请随意这样做。

答案 2 :(得分:0)

调用dispose后,将object设置为null是我通常遵循的方法。然后,您不需要创建任何异常,因为将抛出null异常,并且它似乎是正确的方式。

当一个对象为null时,它是否为空并不重要,因为它被处理掉了;或者它为null,因为它未初始化或为null,因为它显式设置为null。消费者应该知道它是空的,而不是无效的基本行为。