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
或者,更好的是,我具体想到的是:我有一个对象,它执行高度专业化的图形位块传输,并具有
Begin()
和 End()
方法(DirectX 和 XNA 中也存在这种设计)。相反...
using(blitter.BlitOperation()) {
// Do work
}
// Use result
它似乎更自然和可读,但它是否不可取,因为它使用了
IDisposable
接口和 using
语句来达到意想不到的目的?换句话说,这是否与以非直观方式过度加载运算符相同?
我属于少数派。大多数人似乎使用“使用”作为通用目的“即使抛出异常,我也希望运行一些清理代码”机制。
我不喜欢这个,因为(1)我们已经有一个机制,称为“try-finally”,(2)它使用一个功能来实现它不想要的目的,以及(3)如果调用清理代码很重要,那么为什么它在被调用的地方不可见呢?如果它很重要,那么我希望能够看到它。
基本的经验法则:如果我可以阅读你的代码并理解它在做什么以及你的意图是什么,那么它是可以接受的。另一方面,如果您需要解释您做了什么,或者为什么这样做,那么维护代码的初级开发人员可能会遇到麻烦。
还有许多其他模式可以通过更好的封装来实现这一点。
底线:这种“技术”不会给你带来任何好处,只会让其他开发人员感到困惑。
blitter.BlitOperation(delegate
{
// your code
});
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");