在.NET中实现IDisposable模式的一部分是检查对象是否已在所有方法/属性中进行了处理,如:
void SomeMethod()
{
if (Disposed)
throw new ObjectDisposedException("Object already disposed", (Exception)null);
...
}
我想要一个轻量级的工具,它可以在构建后的步骤中为所有实现IDisposable模式的类注入代码,而不是用这种管道代码来扰乱代码。有什么建议吗?
不要在Dispose((方法中编写这样的代码。多次处理对象不是逻辑错误。事实上,这种情况非常常见,传递给StreamReader的FileStream就是一个经典的例子。
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
using (var sr = new StreamReader(fs)) {
// etc..
}
}
fs对象在此处被释放两次。如果有任何例外,避免这种情况只会带来麻烦。
如果你并没有像你的问题所说的那样真正谈论"实现Dispose模式",而是只想在任何方法中检查对象是否被处理:保持KISS:
private bool CheckDisposed() {
if (this.disposed) throw new ObjectDisposedException();
}
或者直接内联。在异常消息中添加任何措辞都是不必要的。例外情况非常清楚,而且只有一件事。当然,只有在调试会话和单元测试中才会出现这种异常。向它投掷AOP武器并非不可能,但可能有点过于严厉。当一个属性只替换一行代码时,很难取得成功。不要将其注入Dispose((方法:(
PostSharp可能会允许您这样做,尽管它似乎不再是免费的。
我相信,您应该能够在方法边界方面添加代码,然后将其添加到每个方法中(您可能希望排除Dispose方法本身(
EDIT仍然有免费的社区版
在对象被释放后,从所有成员抛出ObjectDisposedException并不总是合适的。甚至来自除Dispose之外的所有成员。举个例子,在WinForms Form以模式显示后,通常会访问它暴露的属性:
using(MyForm myForm = ...)
{
myForm.ShowDialog();
}
...
// Access myForm properties that correspond to values of controls in MyForm.
或者另一个例子:在FileStream被释放后,没有必要阻止调用方访问FileStream.Name
——事实上,FileStream类确实允许这样做。
因此,我只需要保留一个代码片段,以便手动粘贴到那些明确需要此功能的成员中:不要盲目生成可能不合适的代码。
还有一点需要注意:IDisposable类有两个大类:一个是拥有IDisposaable成员的类,另一个是直接拥有非托管资源的类。第一种情况是迄今为止最常见的,尤其是在您自己的应用程序代码中。
在第一种情况下,检查可能是多余的:如果需要的话,让拥有的IDisposable对象抛出ObjectDisposedException
就足够了。不访问拥有的IDdisposable对象的成员不需要抛出。
在第二种情况下,您确实需要从任何可能尝试访问非托管资源的成员抛出ObjectDisposedException
,但不需要从任何其他成员抛出。通常,您会将对非托管资源的访问打包为少数私有成员:这些成员可能是唯一需要抛出ObjectDisposedException
的成员。