不好的做法? 非正式使用c#的using语句

C#具有using语句,特别适用于IDisposable对象。 据推测, using语句中指定的任何对象都将拥有某种应该确定性释放的资源。

然而,在我看来,编程中有许多设计具有单一的,明确的开始和结束,但缺乏内在的语言支持。 using构造提供了使用代码编辑器的内置特征的机会,至少清楚且自然地突出了这种设计或操作的范围。

我想到的是经常以BeginXXX()EndXXX()方法开始的那种操作,尽管有很多不同的风格,例如涉及“开始”和“连接”的异步代码执行。

拿这个天真的例子吧。

 webDataOperation.Start(); GetContentFromHardDrive(); webDataOperation.Join(); // Perform operation that requires data from both sources 

相反,如果Start方法返回IDisposable.Dispose方法执行连接操作的对象,该怎么办?

 using(webDataOperation.Start()) { GetContentFromHardDrive(); } // Perform operation that requires data from both sources 

或者,更好的是,我特别想到的是:我有一个高度专业化的图形blitting的对象,并且有一个Begin()End()方法(DirectX和XNA中也有一个设计)。 代替…

 using(blitter.BlitOperation()) { // Do work } // Use result 

它似乎更自然,更易读,但它是不可取的,因为它使用IDisposable接口和using语句用于非预期目的? 换句话说,这是否与以非直观的方式运算符操作符相同

这是一种完全可以接受的做法。 这些被称为因子类型, 框架设计指南建议这样做。

基本上,如果类型包装具有特定生命周期的操作,则使用IDisposable和using语句将成为适当的考虑因素。

我实际上也在这里写了关于这个特定主题的博客。

我建议不要这样做; 我的信念是代码是与代码的维护者有效地沟通,而不是编译器,并且应该记住维护者的理解。 我尝试仅使用“使用”来处置资源,通常是非托管资源。

我是少数。 大多数人似乎使用“使用”作为一般目的“我想要一些清理代码运行,即使抛出exception”机制。

我不喜欢这个,因为(1)我们已经有了一种机制,称为“try-finally”,(2)它使用了一个function,它不是为了它的目的,以及(3)如果调用清理代码是重要的是,为什么它在被调用时不可见? 如果它很重要那么我希望能够看到它。

只因为你可以(或因为Phil Haack说它没关系),并不意味着你应该这样做。

基本的经验法则:如果我能够阅读您的代码并了解它正在做什么以及您的意图是什么,那么它是可以接受的。 另一方面,如果你需要解释你做了什么,或者为什么要这样做,那么可能会让初级开发人员在维护代码时绊倒。

还有许多其他模式可以通过更好的封装来实现这一目标。

底线:这种“技术”不会给你带来任何好处,只会让其他开发者感到困惑。

这是一种常见的模式,但就个人而言,我认为没有理由滥用IDisposable,因为当你能以更明显的方式与匿名代表和/或lambdas达到同样的效果时; 即:

 blitter.BlitOperation(delegate { // your code }); 

我认为你应该使用IDisposable来实现它的目的,而不是别的。 也就是说,如果可维护性对您很重要。

我说它是可以接受的 – 事实上,我已经在一些项目中使用它,我希望在特定代码块的末尾触发一个动作。

Wes Deyer在他的LINQ to ASCII Art程序中使用它,他称之为动作一次性(Wes在C#编译器团队工作 – 我相信他的判断:D):

http://blogs.msdn.com/wesdyer/archive/2007/02/23/linq-to-ascii-art.aspx

 class ActionDisposable: IDisposable { Action action; public ActionDisposable(Action action) { this.action = action; } #region IDisposable Members public void Dispose() { this.action(); } #endregion } 

现在您可以从函数返回它,并执行以下操作:

 using(ExtendedConsoleWriter.Indent()) { ExtendedConsoleWriter.Write("This is more indented"); } ExtendedConsoleWriter.Write("This is less indented");