19

C# 有using语句,专门针对 IDisposable 对象。据推测,using语句中指定的任何对象都将持有某种应该被确定性释放的资源。

然而,在我看来,编程中有许多设计都有一个单一的、明确的开始和结束,但缺乏内在的语言支持。该using构造提供了使用代码编辑器的内置功能的机会,以至少清晰自然地突出此类设计或操作的范围。

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

举这个天真的例子。

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()andEnd()方法(DirectX 和 XNA 中也存在这种设计)。反而...

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

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

4

6 回答 6

20

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

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

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

于 2009-07-07T23:54:35.630 回答
12

I recommend against it; my belief is that code is to effectively communicate with the maintainer of the code, not the compiler, and should be written with the maintainer's comprehension in mind. I try to use "using" only to dispose of a resource, typically an unmanaged resource.

I am in a minority. Most people it seems use "using" as a general purpose "I want some cleanup code to run even if an exception is thrown" mechanism.

I dislike this because (1) we already have a mechanism for that, called "try-finally", (2) it uses a feature for a purpose it was not intended for, and (3) if the call to the cleanup code is important, then why isn't it visible at the point where it is called? If it is important then I want to be able to see it.

于 2009-07-08T05:51:19.460 回答
6

Just because you can (or because Phil Haack says it's okay), doesn't mean you should.

The basic rule of thumb: if I can read your code and understand what it's doing and what your intent was, then it's acceptable. If, on the other hand, you need to explain what you did, or why you did it, it's probably going to trip up junior developers maintaining the code.

There are many other patterns that can accomplish this with better encapsulation.

The bottom line: this "technique" buys you nothing and only acts to confuse other developers.

于 2009-07-08T00:12:42.087 回答
5

It's a common pattern, but personally, I believe that there's no excuse to abuse IDisposable like that when you can achieve the same effect in a much more obvious way with anonymous delegates and/or lambdas; i.e.:

blitter.BlitOperation(delegate
{
   // your code
});
于 2009-07-08T00:05:47.870 回答
2

我认为您应该将 IDisposable 用于它的用途,而不是别的。也就是说,如果可维护性对您很重要。

于 2009-07-07T23:53:58.363 回答
0

I'd say it's acceptable - in fact, I've used it in some projects where I wanted to have an action triggered at the end of a specific code block.

Wes Deyer used it in his LINQ to ASCII Art program, he called it action disposable (Wes works on the C# compiler team - I'd trust his judgment :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
}

Now you can return that from a function, and do something like this:

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

ExtendedConsoleWriter.Write("This is less indented");
于 2009-07-07T23:58:50.117 回答