是否存在您不想处理超出范围的 IDisposable 对象的情况?

问题描述 投票:0回答:3

我最初来自 C++ 背景,其中

going out of scope
意味着调用析构函数,而在该析构函数中,您可以清理所有内容。析构函数不是稍后在某个不确定的时间调用的东西(比如在 C# 中)。

C# 的新手我已经阅读了很多关于一次性模式的文章(因为在过去的一年里我犯了很多错误,导致大量未管理的资源没有被清理,导致程序崩溃)并且令人沮丧的是它似乎语言使它变得更容易

to accidentlly implement incorrectly
比它更容易
to accidentlly implement correctly
.

举个例子:

public void DoSomething() {
    using ClassThatImplementsIDisposable obj = new ClassThatImplementsIDisposable();
    // do stuff
}

在上面(我认为)我已经正确地实现了一次性类的使用。也就是说,当我超出范围时,

Dispose
方法将被正确调用,因为我添加了
using
关键字。

但是我在开发的时候发现大部分时候我记得加

using
关键字,但偶尔我可能会忘记加导致资源未管理的问题,这让我想知道:

是否有过我想创建一个实现 IDisposable 的对象并且该变量将超出范围的情况(并且超出范围我也意味着当传递的对象的引用计数变为零时周围)我不想处理它?例如:

public void DoSomething() {
    // is there ever a reason to purposefully leave off 'using'
    // here on a variable that will go out of scope
    ClassThatImplementsIDisposable obj = new ClassThatImplementsIDisposable();
    // do stuff
}

如果有以上情况(我想不出来):

  • 在我看来,如果 C# 语言不给我们
    using
    关键字(这意味着当引用计数变为零时所有 IDisposable 对象将被隐式处理),那么 C# 语言对程序员来说会更安全
    notusing
    关键字用于您不想处理的奇怪情况(再次询问是否有这种情况)
c# idisposable
3个回答
2
投票

当然有,比如你在函数中构造一个

IDisposable
,返回出来,然后调用者将它添加到一个数组中进行安全保存。作为一个真正退化的例子,这就是构造函数所做的。

在我看来,如果程序员不给我们 using 关键字,C# 语言对他们来说会更安全(这意味着当引用计数变为零时,所有 IDisposable 对象都将被隐式处理)

然后你需要阅读更多关于托管内存如何工作的内容。一方面没有引用计数,另一方面你所描述的今天已经发生了

Dispose
的要点是强制它以确定性的方式自行清理,而不是在垃圾收集器决定时间时清理。这对于文件句柄、套接字、Sql Server 句柄、GDI+ 绘图、窗口等操作系统句柄非常重要


0
投票

好吧,你不能证明某些东西不存在,所以我不能肯定地说没有用例。

但是,如果您不调用

Dispose
,那么在某些时候(您无法控制)垃圾收集器会为您销毁该对象。所以没有不调用 dispose 的实际理由——你只是将处置的控制权交给了运行时。

调用 dispose 有明确的实际原因(正确释放 unmanaged 资源是一个很大的资源)。

这意味着当引用计数变为零时,所有 IDisposable 对象都将被隐式处理

它们是,只是不是立即,因为它可以在内存压力或足够的备用资源来完成时在后台完成,而不会出现运行时瓶颈。


0
投票

是否有过这样的情况,我想创建一个实现 IDisposable 的对象,并且该变量将超出范围......我不想处理它?

那将是对一次性模式的滥用。

我不会说没有人曾经以这种方式滥用模式(

DbDataReader
和朋友想到的是一个很诱人的领域),但这绝对不是你在每天的代码中都能找到的东西。

但是问题中的其他内容让我担心:

在过去的一年里,我犯了很多错误,导致了巨大的内存泄漏

IDisposable 与内存有NOTHING关系。它旨在与 unmanaged 资源一起使用,并且在 .Net 中我们有一个垃圾收集器,它已经在那里管理内存。

事实上,大多数 C# 类都应该 Dispose() 方法和终结器。

唯一的例外是事件处理程序,其中对事件的订阅可能无意中持有对对象的引用,从而阻止垃圾收集器持有它。在这种情况下,您可以使用 IDisposable 来清理它。

© www.soinside.com 2019 - 2024. All rights reserved.