在没有资源的类上实现IDisposable有什么好处吗?
在C#中,如果一个类,如一个经理类,没有资源,是否有任何好处: IDisposable
?
简单的例子:
public interface IBoxManager { int addBox(Box b); } public class BoxManager : IBoxManager { public int addBox(Box b) { using(dataContext db = new dataContext()){ db.Boxes.add(b); db.SaveChanges(); } return b.id; } }
如果使用BoxManager,如果它也实现了IDisposable,那么在使用内存时会有什么好处吗? public class BoxManager : IBoxManager , IDisposable
例如:
BoxManager bm = new BoxManager(); bm.add(myBox); bm.dispose();//is there benefit to doing this?
在types上实现IDisposable
只有两个原因
- 该types包含本地资源,在不再使用该types时必须将其释放
- 该types包含
IDisposable
types的字段
如果这些都不是真的,那么不要实现IDisposable
编辑
有几个人提到IDisposable
是实施开始/结束或预订操作的好方法。 虽然这不是IDisposable
原意,但确实提供了一个非常好的模式。
class Operation { class Helper : IDisposable { internal Operation Operation; public void Dispose() { Operation.EndOperation(); } } public IDisposable BeginOperation() { ... return new Helper() { Operation = this }; } private void EndOperation() { ... } }
注意:实现这种模式的另一个有趣的方式是使用lambdas。 而不是给一个IDisposable
回给用户,并希望他们不要忘记调用Dispose
让他们给你一个lambda,他们可以在其中执行操作,并closures操作
public void BeginOperation(Action action) { BeginOperationCore(); try { action(); } finally { EndOperation(); } }
如果您没有明确使用Dispose()
方法,那么在一次性版本和非一次性版本之间不会有一点区别。
虽然你的代码不会受益于实现IDisposable,但我不能同意这里的其他观点,说IDisposable只是(直接或间接)免费的本地资源。 只要对象在生命周期结束时需要执行清理任务,就可以使用IDisposable。 与using
一起using
非常有用。
一个非常受欢迎的例子:在ASP.NET MVC中, Html.BeginForm
返回一个IDisposable。 创build时,对象打开标记,当Dispose被调用时,它closures它。 没有涉及本地资源,但仍然很好地使用IDisposable。
不,如果你没有做一些有用的事情,比如释放你的类可能在Dispose
方法中保留的非托pipe资源,那么没有任何好处。
混淆的一个主要问题是,究竟是什么构成了“资源”,可能不适用于你的情况,而是经常出现。 从对象的angular度来看,非托pipe资源是外部实体( )代表它“做”( *)的东西,外部实体将继续这样做 – 损害其他实体 – 直到被告知停止。 例如,如果一个对象打开一个文件,承载该文件的计算机可能会授予该对象独占访问权限,除非或者直到通知不再需要独占访问权限,否则拒绝Universe中的其他人使用它。
(*)可以是任何地方的任何地方; 甚至可能不在同一台计算机上。
(**)或某种方式来改变外部实体的行为或状态
如果一个外部实体代表一个被放弃和消失的对象做某事,而不先让实体知道它的服务不再需要,外部实体将无法知道它应该停止代表对象不复存在。 IDisposable提供了一种避免这个问题的方法,它提供了一个通知对象的标准方法,当他们的服务不需要的时候。 一个不再需要服务的对象通常不需要向任何其他实体请求任何进一步的好处,因此能够请求任何代表它的实体停止这样做。
为了允许在没有调用IDisposable.Dispose()
的情况下放弃对象,系统允许对象注册一个名为Finalize()
的“故障安全”清理方法。 因为无论什么原因,C#的创build者不喜欢Finalize()
这个术语,这个语言需要使用一个名为“析构函数”的构造,这个构造可以完成同样的事情。 请注意,一般来说, Finalize()
会掩盖而不是解决问题,并且可能会造成自己的问题,所以应该谨慎使用。
“被pipe理的资源”通常是给实现IDisposable
的对象赋予的名称,并且通常(虽然不总是)实现终结器。
不,如果没有(托pipe或非托pipe)资源,则不需要IDisposable
。
小警告:有些人使用IDisposable清理事件处理程序或大内存缓冲区,但是
- 你似乎没有使用这些
- 无论如何,这是一个可疑的模式。
从我个人的经验(在这里的讨论和其他post证实),我会说,可能有一个情况,你的对象使用大量的事件,或不是大量的,但频繁的订阅和取消订阅事件有时导致对象不是垃圾收集。 在这种情况下, 我 Dispose
退订我订购的对象之前的所有事件。
希望这可以帮助。
如果你想using () {}
语法,那么IDisposable
也是很好的select。
在使用ViewModels的WPF项目中,我希望能够暂时禁用NotifyPropertyChange
事件。 为了确保其他开发人员能够重新启用通知,我写了一些代码,以便能够编写如下内容:
using (this.PreventNotifyPropertyChanges()) { // in this block NotifyPropertyChanged won't be called when changing a property value }
语法看起来不错,易于阅读。 为了工作,需要编写一些代码。 您将需要一个简单的一次性对象和计数器。
public class MyViewModel { private volatile int notifyPropertylocks = 0; // number of locks protected void NotifyPropertyChanged(string propertyName) { if (this.notifyPropertylocks == 0) { // check the counter this.NotifyPropertyChanged(...); } } protected IDisposable PreventNotifyPropertyChanges() { return new PropertyChangeLock(this); } public class PropertyChangeLock : IDisposable { MyViewModel vm; // creating this object will increment the lock counter public PropertyChangeLock(MyViewModel vm) { this.vm = vm; this.vm.notifyPropertylocks += 1; } // disposing this object will decrement the lock counter public void Dispose() { if (this.vm != null) { this.vm.notifyPropertylocks -= 1; this.vm = null; } } } }
这里没有资源可以处理。 我想要一个干净的代码与一种try / finally语法。 使用关键字看起来更好。
有没有任何好处:IDisposable?
但是,在你的具体例子中看起来并不是这样:即使你没有任何IDisposable
字段,也有一个很好的理由来实现IDisposable
:你的后代可能会这样做。
这是IDisposable
突出显示的IDisposable的大型架构问题之一:您的母亲从未告诉您有关资源释放的信息 。 基本上,除非你的class级是封闭的,否则你需要决定你的后代是否有可能拥有IDisposable
成员。 这不是你可以实际预测的。
所以,如果你的后代可能有IDisposable
成员,那么在基类中实现IDisposable
可能是一个很好的理由。
简短的回答是否定的。 但是,您可以在对象生命周期结束时巧妙地使用Dispose()
执行的性质。 一个已经给了一个不错的MVC例子( Html.BeginForm
)
我想指出IDisposable
和using() {}
语句的一个重要方面。 在Using
语句的末尾,使用上下文对象(当然,它必须实现了IDisposable
接口Dispose()
自动调用Dispose()
方法。
还有一个原因,没有人提到(虽然它是辩论,如果它真的值得):对话说,如果有人使用一个类实现IDisposable
,它必须调用其Dispose方法(显式或通过“使用”语句)。 但是,如果一个类的V1(在你的公共API中)不需要IDisposable,但V2呢? 从技术上讲,它不会破坏向后兼容性,为一个类添加一个接口,但是由于这种传达 ,它是! 因为您的代码的旧客户端不会调用其Dispose方法,并可能导致资源不被释放。 (几乎)避免它的唯一方法是在任何情况下实施IDisposable,您怀疑您将来需要它,以确保您的客户始终呼叫您的Dispose方法,以便确实需要某一天。 另一个(也许更好)的方法是实现上面的API中V2的JaredPar提到的lambda模式。