Dispose应该做什么 - 只清理资源或执行一些“业务逻辑”?

时间:2014-02-15 10:29:01

标签: c# .net design-patterns architecture idisposable

考虑到IDisposable的语义,除了清理资源之外,Dispose应该做什么呢?

我看到许多类使用Dispose方法来启动关闭进程和其他一些东西,而不只是执行“资源清理”工作。例如,如果你的类中有一个线程需要关闭,那么你会期望调用Dispose正常关闭这个线程吗?

恕我直言,我会在这个对象上实现一个停止/关闭方法,然后优雅地关闭那里的线程,而在Dispose中我会检查线程何时还活着,只需在它上面调用Abort(暗杀样式:))。

同样的例子可以是定时器,以及所有其他资源,在完成你使用该对象之前可以有某种终止过程。

.NET中两个冲突设计的例子:

  • Windows服务的ServiceBase具有OnStop和Dispose to 覆盖。
  • 来自OWIN的WebApp.Start自助托管让你回来了 IDisposable我认为该服务在某处停止 处理过程。

2 个答案:

答案 0 :(得分:2)

很难,我使用dispose 只做做业务逻辑。例如:

public class UsingBase : IDisposable
{
    protected Action end;
    public UsingBase(Action start, Action end) { this.end = end; if (start != null) start(); }
    public void Dispose() { if (end != null) end(); }
    public void Cancel() { end = null; }
}

class HideCursor : UsingBase { public HideCursor() : base(() => Console.CursorVisible = false, () => Console.CursorVisible = true) { } }

public static void DisplayTitle(...)
{
    ...
    using (new HideCursor())
    {
       //Display the title
    }
    ...
}

虽然有些人可能认为这是滥用语言,但我从ASP.net API中得到了这个想法。

@using (Html.BeginForm())
{
    ...
}

回到你的问题

  

例如,如果您在类中有一个线程,则需要   关闭,你会期望调用Dispose正常关闭   这个帖子?

我喜欢它,当它有意义时 - 因为我经常使用对象使用它,让它自己处理它。当然,如果您清楚地记录了您的逻辑,并且有明确的理由将“优雅停止”与“处置”区分开来,那么这可能有用。

或换句话说 - 我不想无缘无故地这样做:

using (var blah = new Blah())
{
...
...
...
Blah.SpecialDispose();
}//Blah.Dispose();

因为它会导致使用试图停止的确切问题 - 人们忘记编写正确的包装代码(例如,最后尝试)。


编辑:

总结。是的,业务逻辑可以完成Dispose。是的,Dispose可以很好地处理事情。这些是你提出的主要问题。但是,这并不一定否定可能的用例,其中Dispose被用作“最后手段”并且在其行为中更加突然。听起来你对自己的用例充满信心,在这种情况下继续。如果您仍想要反馈,我建议发布一个与您的实际用例相关的更具体的问题。

答案 1 :(得分:1)

不要考虑IDisposable合同,而是将IDisposable视为一般Object合同的一部分更有帮助,该合同规定对象不应要求任何形式的在放弃之前注意 IDisposable.Dispose之外的其他文件(未实现IDisposable的对象根本不需要任何通知)。 <{1}}方法应该做任何事情,并且在安全放弃对象之前需要完成所有事情。

这个问题的唯一方面是执行清理时可能会出现异常,Dispose无法知道在这种情况下它应该做什么。如果在正常(非异常)程序执行期间调用Dispose,则在清理失败时应抛出异常。但是,如果在从异常中展开堆栈时调用它,则它可能抛出的任何异常通常都会破坏先前异常的所有证据(因此通常会更好地使它无声地失败而不是抛出异常)。不幸的是,Dispose无法确定哪种情况适用,因此无法在清理失败的情况下始终如一地做正确的事情。