【问题标题】:How do I dispose of my Controllers when their fields implement IDisposable?当控制器的字段实现 IDisposable 时,我如何处置我的控制器?
【发布时间】:2012-05-24 04:14:32
【问题描述】:

我的控制器继承自一个包含实现 IDisposable 的字段的类。所以我的第一直觉是写:

public abstract class EventRepositoryControllerBase : Controller
{
    protected EventRepository eventRepos { get; private set; }

    public EventRepositoryControllerBase(EventRepository eventRepos)
    {
        this.eventRepos = eventRepos;
    }

    public override void Dispose()
    {
        try
        {
            base.Dispose();
        }
        finally
        {
            eventRepos.Dispose();
        }
    }
}

但这不会编译,因为 Controller 没有将 Dispose 方法标记为虚拟/覆盖。所以现在我想我被困住了。即使我将我的方法标记为新方法,框架是否不会保存类型为 Controller 的引用,因此我的方法将永远不会被调用?有关如何解决此问题的建议?

更新

于是我查看了 MVC3 源码,看到了这个:

 public void Dispose() {
        Dispose(true /* disposing */);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing) {
    }

所以我想我会把我的代码放在第二种方法中。但不确定这种行为是否是合同规定的。

【问题讨论】:

  • 无论如何你都不应该在控制器中处理eventReposEventRepositoryControllerBase 没有创建它,所以它不应该杀死它。构造函数的实现方式表明eventRepos 的生命周期超出了EventRepositoryControllerBase 的生命周期

标签: c# asp.net-mvc asp.net-mvc-3 model-view-controller idisposable


【解决方案1】:

如果IDisposable.Dispose 是使用非密封方法实现的,则派生类型的代码将在基本类型清理代码之前和之后运行;因为 GC.SuppressFinalize 不应该在派生类型完成其清理之后才被调用(包括可能在基类型完成清理之后发生的任何部分),所以 GC.SuppressFinalize 是在一个密封的实现中制作的,它反过来调用一个签名为void Dispose(bool)的虚方法。

请注意,虽然从概念上讲,在密封包装器中调用虚拟方法是个好主意,但 Microsoft 的实现存在一些缺陷。最值得注意的是:

  1. 因为它在基类中使用了一个私有标志来指示对象是否已经被释放,但在包装方法中没有使用该标志,所以每个希望避免重复释放的派生类也必须有自己的释放标志;
  2. 派生的 `Dispose` 调用可能会在以下三种情况下退出:
    1. 可以正常返回
    2. 它可能会抛出异常,但仍然实现了可以实现的所有目标,因此仍然应该抑制终结(例如,因为 `IDisposable` 日志对象包装了文件,并且文件数据在关闭时未成功写入)。一种丑陋的情况,但是将对象注册为最终确定无济于事。
    3. 它可能会引发异常,在该对象应仍符合最终确定条件的情况下。
    Microsoft 的 `Dispose` 模式没有提供区分后两种选择的方法。虽然在许多情况下为基于终结的清理而注册的对象可能是无害的,但如果使用“Finalize”方法记录调用“Dispose”的失败可能会导致混淆。
  3. 这意味着对象应该经常持有一些它们通过终结清理的资源和一些仅通过“Dispose”清理的资源,并且不通过终结清理任何东西的非密封类型应该为派生类型提供准备这可能。在实践中,具有终结器的类应避免持有对终结器不需要的任何对象的引用;需要终结的资源应该被封装到它们自己的类对象中,然后这些对象应该由不必担心终结它们的类持有。

在 Microsoft 找到处理非托管资源的最佳方法之前,Dispose 模式是一个很好的初步尝试。今天,我认为最好将虚拟方法的参数视为用于更改签名的虚拟参数,而不是有意义的东西(即使从包装器链接虚拟方法时应该始终传递True)。

【讨论】:

    【解决方案2】:

    ASP.NET MVC 中的控制器类已正确实现 IDisposable 接口。如需进一步参考,请查看 MSDN 页面上的 this page,其中明确指定了这一点。

    要插入 IDisposible 接口,您需要覆盖您已经找到的受保护的 dispose 方法,并将逻辑放置在其中。

    【讨论】:

      【解决方案3】:

      1) 在你当前的类上实现接口 idisposable 并做你想做的事 2)在您的基类中实现该接口,然后在此类中覆盖它 3)只在你的基类中实现那个接口,不要覆盖 另外,你的代码看起来很奇怪,你有一个抽象类并且你提供了实现逻辑

      【讨论】:

        猜你喜欢
        • 2018-10-07
        • 2021-05-23
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-28
        • 2012-11-07
        • 1970-01-01
        相关资源
        最近更新 更多