C# IDisposable pattern and throwing ObjectDisposedException
本文关键字:throwing ObjectDisposedException and pattern IDisposable | 更新日期: 2023-09-27 18:11:44
给大家一个问题。
在我的公司,我们正在开发一个在Microsoft的MVC框架内运行的应用程序。我们正在实现的控制器类继承自 MVC 基类控制器。例:
public class MyController: Controller
{
protected bool IsDisposed { get; set; }
… various methods…
}
我们在团队中进行的讨论围绕着Dispose((模式。本质上,这涉及实现 IDisposable 接口,最好根据 Microsoft 认可的模式。
例如,请参阅此链接:http://msdn.microsoft.com/en-us/library/fs2xkftw%28v=vs.110%29.aspx
有趣的是,我们的控制器类不拥有任何资源,无论是托管的还是托管的。因此,Dispose(bool( 的实现大大简化:
protected override void Dispose(bool disposing)
{
IsDisposed = true;
base.Dispose(disposing);
}
对于以下方法中使用的 IsDisposed
属性的使用(或需要(存在一些分歧:
protected void ThrowIfDisposed()
{
if (IsDisposed) throw new ObjectDisposedException(“MyController”);
}
然后,在每个执行"实际"工作的方法的开头调用此方法。这里的想法是,不应再次使用已释放的对象,因此它应该抛出 ObjectDisposedException。另一种观点是,由于Dispose(bool)
"什么都不做"(除了设置IsDisposed
属性并在基类上调用Dispose(bool)
(,"释放"对象实际上并不处于不可用的状态,因此没有理由抛出。因此,甚至没有理由实施Dispose(bool)
.
反对这一点的一个论点是,MyController 应该在释放它并调用它的方法之一时抛出,以便在将来的版本中添加托管和/或非托管资源时,它的行为不会改变。
反对最后一点的论点是,MyController 不应该在未来的版本中添加任何资源,而是应该从将来需要添加资源时派生它。另一个问题是:为什么(库(类控制器不实现ThrowIfDisposed()
或类似的东西?
所以,总结一下,第一派想要实施Dispose(bool)
,如上所示ThrowIfDisposed()
,第二派认为它们是不必要的,并希望废除它们。
我从这两种观点中都看到了优点,无法真正下定决心。意见?
有趣的是,我们的控制器类不拥有任何资源,无论是托管的还是托管的。
然后,您不需要 IDisposable 模式。
然后,在每个执行"实际"工作的方法的开头调用此方法[
ThrowIfDisposed()
]。
这里的问题是:为什么?
如果您确实想跟踪可用/放弃的状态,请不要将其称为 IsDisposed。
为什么(库(类控制器没有实现ThrowIfDisposed((或类似的东西?
因为它没有用。
回到开头:为什么有人认为这是必要的?这是干什么用的?
看来你可以把它撕掉。
如果一个对象在被释放后收到一个请求,那么请求不应该因为ObjectDisposedException
以外的任何原因而失败——这意味着它不应该导致NullReferenceException
、产生垃圾数据、系统崩溃或做任何其他类似的事情。 这并不意味着请求不应该成功 - 只是ObjectDisposedException
应该是唯一的失败模式。
至于IsDisposed
,在大多数情况下,我真的看不出它有多大用处。 不知道对象是否已被释放的代码通常不会对对象的状态了解得足够多,无法知道它是否可能由于其他原因而无法使用;因此,不知道对象是否已被释放的代码通常不应该对它做任何事情,除非(在某些情况下(Dispose
它,并且在大多数情况下,如果尚未释放对象,人们想要对对象调用Dispose
,应该简单地无条件调用Dispose
。 拥有一个方法MayNeedDisposing
可能会有一些价值,该方法将为具有非平凡Dispose
方法的对象返回true
,直到它们被释放,但是这样的方法可以无条件地为具有空Dispose
方法的对象返回false
[例如,在类注册回调纯粹是为了调用Dispose
的情况下, 事先测试MayNeedDisposing
可能是一个有用的优化]。
最后,关于类或接口是否应该实现或继承IDisposable
,问题不在于类型本身是否获取资源,而在于对获取资源的事物的最后一个幸存引用是否可以存储在该类型中。 例如,即使绝大多数IEnumerator<T>
实现不获取资源,有些实现会获取资源,并且在许多情况下,对此类对象的唯一引用将存储在类型为 IEnumerator<T>
的变量中,由不知道相关对象是否有任何资源的代码持有。 请注意,非泛型IEnumerator
不会实现IDisposable
但某些实现会获取资源。 因此,如果调用 IEnumerable.GetEnumerator
的代码实现了 IDisposable
,则需要在返回的枚举器上调用 Dispose
。 IEnumerator
不继承IDisposable
这一事实并不能免除接收IEnumerator
实现的代码,该实现也实现了IDisposable
调用Dispose
的责任 - 它只会使此类代码更难履行该责任。
派系是绝对正确的。别这样。
以所描述的方式和给出的原因实现IDisposable至少违反了三个良好的原则。
- 你不需要它。http://c2.com/cgi/wiki?YouArentGonnaNeedIt
- 做最简单的可能奏效的事情。 http://www.xprogramming.com/Practices/PracSimplest.html
- 保持简单愚蠢。 https://en.wikipedia.org/wiki/KISS_principle
这在各个层面上都是错误的。别这样。