调用Dispose到底做了什么?

时间:2016-12-14 14:57:52

标签: .net memory-management garbage-collection dispose

我一直在努力增加对垃圾收集的理解,管理&非托管资源,以及适当的设计原则"关于内存管理,因为我有兴趣进入"较低级别"编程和那种性质的东西。

我了解您假设使用using阻止或其他一些解决方案来确保这些非托管资源实际上已被处理,但我不明白发生了什么事情。

我在MSDN上查看了这篇文章:Implementing a Dispose Method,并对此特定行感到困惑:

  

为了确保始终适当地清理资源,Dispose方法应该可以多次调用,而不会抛出异常。

让我们看一下它们为dispose模式提供的示例代码:

class DerivedClass : BaseClass
{
   // Flag: Has Dispose already been called?
   bool disposed = false;

   // Instantiate a SafeHandle instance.
   SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

   // Protected implementation of Dispose pattern.
   protected override void Dispose(bool disposing)
   {
      if (disposed)
         return; 

      if (disposing) 
      {
         handle.Dispose();
         // Free any other managed objects here.
      }

      // Free any unmanaged objects here.

      disposed = true;

      // Call base class implementation.
      base.Dispose(disposing);
   }
}

相信上面引用的文字基本上是说什么,"我们添加了bool disposed属性,以便我们检查true {{1} }和return如果是这样的话。如果是false,那么我们会处理实际资源。这样我们就不会多次 多次处理某些事情"

但这对我没有意义。如果我们已经摆脱了某个对象,你怎么能再次打电话给Dispose

为了调查,我编写了一个包含以下3行的控制台应用程序:

var cmd = new SqlCommand();
cmd.Dispose();
cmd.Dispose();

这个编译和执行没有问题 - 这是有道理的,考虑到文章中的引用文本。但我不明白实际发生了什么

我设置断点并跨过每一行。调用第一个Dispose后,我希望Visual Studio中的Locals窗口告诉我cmdnull。按照这一思路我问自己,"你如何在Dispose上致电null?"显然,你不能。那么发生了什么?为什么cmd在第一次处理后仍然是SqlCommand个对象?

enter image description here

Dispose做了什么完全,如果我处理了我的对象,为什么它似乎仍然存在于所有意图和目的?

为什么/以下如何编译和运行没有问题?

var cmd = new SqlCommand();
cmd.Dispose();
cmd.CommandText = "I figured this would throw an exception but it doesn't";

2 个答案:

答案 0 :(得分:2)

IDisposable接口由几个消耗类调用,并且 - 正如Dark Falcon已经说明的那样 - 当你将类的用法封装在using块中时。这样可以更轻松地保持非托管资源的清洁。 但Dispose就像任何其他方法一样,不要与析构函数/终结符混淆(这是你显然预期的那样)

答案 1 :(得分:1)

Dispose语句可以为您调用之外,using没有什么特别之处。除此之外,它就像任何其他.NET函数一样。它没有神奇地将任何变量设置为null,导致在再次使用该对象时抛出异常,或者类似的任何变量。

同样,IDisposable不是一个特殊的接口,除了using语句中的对象必须实现它。你可以认为using语句是这样的:

// using(var a = somethingDisposable()) {otherCode();}
var a = somethingDisposable();
try
{
    otherCode();
}
finally
{
    if(a != null)
        ((IDisposable)a).Dispose();
}