我该如何确保处理可能的一次性物品?
我正在开发一个.NET项目,它需要与一些用户定义的类进行交互 – 称为“作业”。 所有作业类必须按顺序实现特定的接口IJob
,以便库使用它们。 有时,作业类可能包含非托管资源,需要明确处理。
如果我事先不知道工作是否需要明确处理,我应该如何确保所有工作在使用后妥善处理? 我自己有一些想法,但是想听听你的意见/建议:
-
使
IJob : IDisposable
,强制所有作业实现Dispose()
方法。 这将允许我using
块中的作业,但由于大多数作业不需要明确处理,这可能会给客户端开发人员带来不必要的混淆。 -
完成涉及
try-finally
块中的作业的所有工作,并finally
使用以确保在作业实现IDisposable
调用Dispose()
。 这使得客户端更容易实现新的作业类 – 不必实现空的Dispose()
方法 – 但它也隐藏了库知道并关心可支配作业的事实。
写完这篇文章之后,我倾向于倾向于解决方案#1,但我仍然认为看到替代解决方案会更好,并且我已经考虑过两者的其他优缺点。
有一个先例:Stream基类是IDisposable nad因此所有Streams后代都是。 但是MemoryStream不需要Disposing。
但是不要以try / finally为目标, using() { }
块是一种更方便的简写。
所以你的选择是:你想要所有的工作都是IDisposable还是只有一些?
第一个选项会产生很小的开销,第二个选项会在必要时更容易忘记Dispose(using)。
#2是foreach
构造的工作原理。 这也是Autofac集装箱处理的工作原理。
语义上的区别在于你是说一个工作本身是一次性的,还是一个实现可能是一次性的。
从你的例子可以清楚地看出,前者不是真的,工作本身并不是一次性的。 因此,我建议使用#2,但使用扩展方法来集中try/finally
:
public static void Execute(this IJob job) { try { job.Run(); } finally { var disposableJob = job as IDisposable; if(disposableJob != null) { disposableJob.Dispose(); } } }
我这样想。 我宁愿开发人员实现一个空的Dispose
方法,而不是忘记实现一个必要的Dispose
方法。
我会选择#2并记录任何一次性物品将被丢弃。 基本上,如果您拥有对象的所有权,则您有义务处置实现IDisposable的对象。
如果您阅读有效的C#/更有效的C#,比尔瓦格纳给出了相同的建议(我明显同意;-)