【问题标题】:using IDisposable through inheritance通过继承使用 IDisposable
【发布时间】:2015-09-08 08:03:14
【问题描述】:

我正在使用继承并试图了解使用 IDisposable 的最佳方式。下面是我的基类的示例。

我知道,如果我有一个继承自 MyBase 类的类(让我们调用 MyChild),即使 MyChild 没有实现 IDisposable,如果 MyChild 已初始化,则将执行 Dispose 方法(相信我说得对) 如果像下面这样使用,

using(MyChild chl = new MyChild) {// some code};

我想知道的是,我在 MyChild 类中有一个对象,我想确保将其处理掉。我是否必须实现 IDisposable 接口并拥有与 MyBase 类中几乎相同的代码,或者我可以使用 MyBase 类中的代码吗?我猜这就是为什么在 MyBase 类中有一个受保护的虚拟 Dispose 方法的原因?

我的基类

 public class MyBase : IDisposable
 {
        // variables & methods declared here etc

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (myObj != null) releaseObject(myObj);
            }
        }

        private static void releaseObject(object obj)
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        }
 }

【问题讨论】:

    标签: c# .net inheritance


    【解决方案1】:

    void Dispose(bool disposing)protected virtual 是有原因的。您应该覆盖它(并调用基本版本)。

    public class MyChild : MyBase
    {
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Dispose Child's objects
            }
    
            base.Dispose(disposing);
        }
    }
    

    【讨论】:

      【解决方案2】:

      您只需覆盖子类中的 Dispose(bool) 方法即可添加您想要的任何其他处置。

      然而,这是在回避真正的问题——你所做的有些不必要而且有点危险dangerous

      这里的教训是:如果您想调用“Marshal.ReleaseComObject”,您能否 100% 确定没有其他托管代码仍然可以访问 RCW?如果答案是“不”,那就不要打电话。最安全(也是最明智)的建议是完全避免 Marshal.ReleaseComObject 出现在组件可以随时间重复使用和版本化的系统中。

      为您构建的 COM 包装器 .NET 是安全且可管理的,除非绝对必要,否则应避免任何显式处置。甚至Marshal.ReleaseComObject 的文档也提供了一些避免这种情况的充分理由:

      如果在释放 RCW 时正在执行对 RCW 的调用,则可能会发生更严重的错误。在这种情况下,进行调用的线程很可能会导致访问冲突。但是,进程内存可能会损坏,并且进程可能会继续运行,直到由于非常难以调试的原因而失败。

      ...

      因此,只有在绝对需要时才使用 ReleaseComObject。如果要调用此方法以确保 COM 组件在确定的时间释放,请考虑改用 FinalReleaseComObject 方法。

      最后,你必须明白,无论你做什么,都不能保证 COM 对象无论如何都会做任何确定性的处理。这取决于 COM 对象,而不是 .NET 中的运行时可调用包装器。您所做的只是说“不再引用此 COM 对象”。好吧,很明显,这与本地超出范围并最终被垃圾回收时发生的事情几乎相同。

      【讨论】:

      • 感谢您的详细帖子。我正在使用 Microsoft.Office.Interop.Excel 并阅读了有关在后台运行的 excel 进程的许多问题以及在我看到他们使用 Marshal.ReleaseComObject 的示例中。你会建议使用 FinalReleaseComObject 代替吗?
      • @mHelpMe 不,绝对不是。只需合作关闭它 - 在 Excel COM 对象上有类似 Close 或类似的东西来做到这一点。这将立即释放 Excel 进程,不像ReleaseComObject,而且友好得多。
      猜你喜欢
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      • 2010-12-22
      • 1970-01-01
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 2020-01-25
      相关资源
      最近更新 更多