IDisposable接口,终结和非托管资源的定义(IDisposable, Finalizers

2019-07-28 22:44发布

我想确保我的理解IDisposable是正确的,有些事情我还是不是很确定。

IDisposable似乎有两个目的。

  1. 为了提供公约“停摆”按需托管对象。
  2. 为了提供一个约定,以释放被管理对象举行了“非托管资源”。

我的困惑来自于确定哪些方案中有“非托管资源”在起作用。

假设你使用的是Microsoft提供IDisposable -implementing(管理)类(比如数据库或插座相关的)。

  1. 你怎么知道它是否实现IDisposable只是11以上2?
  2. 你是负责确保非托管资源,它可能会或可能不会在内部保持被释放? 如果您要添加一个终结(会是这样的权利的机制呢?)到自己的类调用instanceOfMsSuppliedClass.Dispose()?

Answer 1:

  1. 你怎么知道它是否实现了IDisposable只是1或1以上2?

回答你的第一个问题是“你不应该需要知道”。 如果您在使用第三方的代码,那么你就其摆布到某一点 - 你不得不相信,它的处置本身正确,当你调用Dispose它。 如果你不确定,或者你认为有错误,你总是可以尝试使用反射()拆开它(如果可能的话),并检查了它在做什么。

  1. 我是负责确保非托管资源,它可能会或可能不会在内部保持被释放? 我应该增加一个终结(会是这样的权利的机制呢?)我自己的类调用instanceOfMsSuppliedClass.Dispose()?

你应该很少,如果有的话,需要执行终结你的类,如果你使用的.Net 2.0以上。 终结开销添加到您的类,而且通常没有提供更多的功能,那么你需要与刚刚实施处置。 我会强烈建议您访问这篇文章对正确处置了很好的概述。 在你的情况,你会想打电话instanceofMSSuppliedClass.Dispose()在自己的Dispose()方法。

最终,在对象上调用Dispose()是很好的做法,因为它显式地让GC知道你与资源完成,并允许用户立即清除它的能力,并间接文件的代码通过让其他程序员知道该物体在该点所拥有的资源来完成。 但即使你忘记显式调用它,它最终会当对象是无根的发生(净毕竟是一个管理平台)。 如果你的对象的非托管,将需要清理隐性资源(即有机会的话,消费者可以忘记把它清理干净,并认为这将是有问题的)终结只应实施。



Answer 2:

你应该总是调用Dispose实现IDisposable的(除非他们明确告诉你这是一个有用的规则,像ASP.NET MVC的HtmlHelper.BeginForm)对象。 您可以使用“使用”的声明,以使这个容易。 如果你在你的类挂到一个IDisposable接口的引用作为成员字段,那么你应该使用实现IDisposable 一次性模式来清理这些成员。 如果你运行像的FxCop静态分析工具,它会告诉你同样的。

你不应该试图第二猜测的接口。 如今,这一类可能不使用有关下一版本的非托管资源,但什么?



Answer 3:

你不负责的对象的内容。 Dispose()方法应该是透明的,并且免费它所需要释放。 在这之后,你不负责。

托管资源的资源,就像您创建(托管)C ++,你通过指针和“新”的语句分配内存,而不是“gcnew”语句。 当你创建在C ++类,你负责删除此内存,因为它是本机内存,或不受管理,以及垃圾回收器不会了。 您也可以通过创建元帅分配这个非托管内存,并且,我会承担,不安全的代码。

当使用托管C ++,您不必手动实现IDisposable类两种。 当你写你的解构,它会被编译成一个dispose()函数。



Answer 4:

如果有问题的类是微软提供的(即..数据库等等),然后处理掉(自IDisposable)的处理将最有可能已经被照顾,它只是由你来调用它。 例如,使用一个数据库,标准的做法将如下所示:

//...
using (IDataReader dataRead = new DataReaderObject())
{
   //Call database
}

这是基本相同的写作:

IDataReader dataRead = null;
try
{
    dataRead = new DataReaderObject()
    //Call database
}
finally
{
    if(dataRead != null)
    {
        dataRead.Dispose();
    }
}

据我了解,它总体上是好的做法,你用前者对自IDisposable继承,因为这将保证资源的正常释放对象。

至于使用IDisposable的自己,实现由你。 一旦你从它继承你应该确保该方法包含处置你可能已经手动创建的数据库连接所需要的代码,释放可能保留或阻止该对象的资源被破坏,或者只是清理大的资源池(如图片)。 这也包括非托管资源,例如,代码里面标有“不安全”块基本上非托管代码,可以允许直接存储器操作,这东西肯定需要清理。



Answer 5:

术语“非托管资源”是一个名不副实的东西。 基本概念是成对的行动 - 执行一个操作创建一个需要进行一些清理行动。 打开文件创建一个需要关闭它。 拨号调制解调器创建需要挂断电话。 系统可以生存未能执行清理操作,但后果可能很严重。

当一个对象被表示为“持有非托管资源”,什么是真正的意思是,对象有必要的信息,并推动一些实体进行一些必要的清除操作,而且也没有特别的理由相信,信息和动力的任何地方存在其他。 如果这样的信息和动力的唯一对象被完全废弃,不会发生所需的清除操作。 .Dispose的目的是迫使一对象执行任何所需的清理,使得其可以安全地抛弃了。

以提供针对其放弃的对象,而不首先调用Dispose代码一些保护,该系统允许类为“修订”注册。 如果注册的类的对象被放弃,系统将给予对象将其放弃为好之前其他实体进行清理操作的机会。 有没有保证,以系统如何迅速发现某些物件已被放弃,然而,各种情况下可以防止物体被提供了机会进行清理。 术语“管理资源”有时被用来指代的对象将不得不进行一些清理它放弃前,但它会自动注册并尝试,如果有人不调用Dispose执行这样的清理工作。



Answer 6:

为什么它应该怎么了你?

当可能的I包裹一次性对象的范围中使用。 这调用Dispose在使用结束。 当我不显式调用处理时,我不再需要的对象。

是否为原因1或2的原因是没有必要的。



Answer 7:

是的,你是负责调用Dispose方法-或者更好地利用using的语句。 如果一个对象实现IDisposable ,你应该总是处置它,不管是什么。

using (var myObj = new Whatever())
{
   // ..
}

类似于

{
  var myObj;
  try
  {
     myObj = new Whatever();
     // ..
  } 
  finally
  {
    if (myObj != null)
    {
      ((IDisposable)myObj).Dispose();
    }
  }
} // object scope ends here

编辑 :添加的try /最后感谢Talljoe -哇,这是复杂的得到它吧:)

EDIT2:我不是说你应该使用第二个变种。 我只是想说明,“使用”是一堆代码,可以得到相当混乱和很难得到正确不错的语法糖。



Answer 8:

正在这里缺少一个部分是终结 - 如果我实现IDisposable我的习惯一直是我也有一个终结调用Dispose(),以防万一我的客户不。 是的,它增加了开销,但如果的Dispose()被调用比GC.SuppressFinalize(这)调用消除它。



文章来源: IDisposable, Finalizers and the definition of an unmanaged resource