1

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

我测试了 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 之后,位图对象允许使用 PixelFormat 属性。我应该遵循这种行为吗?

4

3 回答 3

1

我在这个和许多其他问题上的理念是“做有意义的事”。

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

虽然有人可能会争辩说Close应该关闭连接,同时允许使用报告历史信息的属性,而Dispose应该关闭事物并禁止使用这些属性,但我认为这样的区别是没有帮助的。除其他外,人们可能希望连接释放与其关联的所有资源(Close为了允许“重新打开”请求,可能会避免做某事)。Close此外,在和之间的行为没有其他差异的情况下Dispose,我认为没有必要纯粹要求两个单独的方法,这样Dispose可以使统计数据无效。

从某种意义上说,许多IDisposable对象可以被视为具有两部分——一个与外部资源交互的实体,以及一个与托管代码交互并且本身可能具有有限功能的实体。虽然“关注点分离”原则建议这两个部分应该是单独的对象(实际上,当这样的拆分可能会有所帮助时,会有一些尖齿),但在许多情况下,客户端代码会想要持有一个单一的引用,它可以服务于两个目的。该引用将必须实现IDisposable,但处置不应破坏事物的托管代码方面。

例如,考虑 WinFormsFont类。该类封装了两件事:(1) 关于字体(字体、大小、样式等)的信息集合,以及 (2) GDI 字体句柄。当 aFontDisposed 时,它不能再用于绘制文本,但它不会忘记字体、样式等。给定Disposed 字体,可以使用旧字体的信息构建新字体。不幸的是,大多数允许读取此类信息的属性都被 显式无效Dispose,这意味着在许多情况下,如果想要生成一种类似于现有但已处理Font但有一些更改的字体,则必须用从旧字体复制的信息构造一种新字体,基于该字体构造另一种新字体,然后Dispose创建的第一个新字体。拥有一个保存与 typestyle 等相关的信息的类可能会有所帮助FontDescription,以便在想要保存字体描述但不需要 GDI 句柄的情况下,字体描述可以存储在非-disposable 类,但这不是类的设计方式。

于 2013-02-03T00:18:37.497 回答
1

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

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

您给出的位图示例是一个非常可悲的示例,但对于 GDI+ 类并不少见。它们通常具有非常差的错误处理能力。让这不是一个例子。

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

于 2013-02-03T01:31:31.327 回答
0

调用 dispose 后,设置objecttonull是我通常遵循的方法。然后,您不需要创建任何异常,因为会抛出空异常,这似乎是正确的方法。

当一个对象为空时,它是否为空并不重要,因为它已被释放;或者它是空的,因为它没有被初始化,或者它是空的,因为它被显式地设置为空。消费者应该知道它是空的,而不是空的潜在行为。

于 2013-02-02T07:04:07.030 回答