不好的做法? C# 的 using 语句的非规范用法

发布于 2024-07-26 13:04:25 字数 1072 浏览 2 评论 0原文

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 语句来达到意想不到的目的? 换句话说,这是否与以非直观方式重载运算符相同?

C# has the using statement, specifically for IDisposable objects. Presumably, any object specified in the using statement will hold some sort of resource that should be freed deterministically.

However, it seems to me that there are many designs in programming which have a single, definite beginning and end, but lack intrinsic language support. The using construct provides an opportunity to use the built in features of a code editor to, at least, clearly and naturally highlight the scope of such a design or operation.

What I have in mind is the sort of operation that frequently starts with a BeginXXX() and EndXXX() method, though there are plenty of different flavors, such as an asynchronous code execution that involves a "start" and a "join".

Take this naive example.

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

What if, instead, the Start method returned an object whose IDisposable.Dispose method performs the join operation.

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

Or, better yet, what I specifically had in mind: I have an object that does highly specialized graphics blitting and has a Begin() and End() method (a design also present in DirectX and XNA). Instead...

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

It seems to be more natural and readable, but is it inadvisable, seeing as it uses the IDisposable interface and the using statement for unintended purposes? In other words, would this be on par with overloading an operator in a non-intuitive way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

影子是时光的心 2024-08-02 13:04:26

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

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

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

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

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.

迟到的我 2024-08-02 13:04:26

这是一种常见的模式,但就我个人而言,我认为当您可以使用匿名委托和/或 lambda 以更明显的方式实现相同的效果时,就没有理由滥用 IDisposable ; IE:

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

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
});
心如狂蝶 2024-08-02 13:04:26

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

I think you should use IDisposable for what it's intended for, and nothing else. That is, if maintainability matters to you.

悲喜皆因你 2024-08-02 13:04:26

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

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");

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");
可遇━不可求 2024-08-02 13:04:25

这是一种完全可以接受的做法。 这些称为因子类型,

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

我实际上在博客中这个特定主题在这里,还有。

This is a perfectly acceptable practice. These are called Factored Types, and the Framework Design Guidelines recommends doing just this.

Basically, if the type wraps an operation with a specific lifetime, using IDisposable and the using statement becomes an appropriate thing to consider.

I actually blogged about this specific topic here, as well.

烂柯人 2024-08-02 13:04:25

我建议反对; 我的信念是,代码是为了与代码的维护者(而不是编译器)有效地沟通,并且应该在编写时考虑到维护者的理解。 我尝试仅使用“使用”来处置资源,通常是非托管资源。

我属于少数派。 大多数人似乎使用“使用”作为通用目的“即使抛出异常,我也希望运行一些清理代码”机制。

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文