Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果在处置之前复制IDisposable的引用,它还会被处置吗?_C#_.net_Garbage Collection_Idisposable - Fatal编程技术网

C# 如果在处置之前复制IDisposable的引用,它还会被处置吗?

C# 如果在处置之前复制IDisposable的引用,它还会被处置吗?,c#,.net,garbage-collection,idisposable,C#,.net,Garbage Collection,Idisposable,考虑这一点: interface IFoo : IDisposable { } class Program { static void Main() { var foo = GetFoo(); var anotherFoo = foo; using(anotherFoo) { } // Will the object on the heap be marked for collection? // Or will this

考虑这一点:

interface IFoo : IDisposable { }

class Program
{
  static void Main()
  {
    var foo = GetFoo();

    var anotherFoo = foo;

    using(anotherFoo)
    {
    }

    // Will the object on the heap be marked for collection? 
    // Or will this confuse the garbage collector 
    // as we are copying references?
  }
}
这就提出了一个更重要的问题。
Dispose()
实际上做什么?

您描述的“复制引用”对原始对象没有任何作用。这只是通过不同的名称查找同一对象的另一种方式——就像你有一个单独的电子邮件地址,它的邮件总是发送到你的邮箱。无论哪种方式,你都可以到达同一个物体。因此,如果处理一个,那么处理另一个

当您拥有代码时:

using (anotherFoo) 
{
}
您正在使用
using
语法来确保在块完成之前发生的最后一件事是,变量
另一个foo
引用的对象上的
.Dispose
方法将被释放。因此,这与使用(foo){…}执行
完全相同

编辑对评论的响应

首先,也是最重要的一点,
IDisposable
与垃圾收集无关。这是自然发生的。在本例中,由于
foo
anotherFoo
都是局部变量,并且(显然)没有通过闭包、方法调用等从方法中转义,因此几乎在方法调用完成后,它们就会被GC'ed


另一方面,
IDisposable
纯粹是为了允许您释放(通常)外部资源,如文件、UI原语、套接字等操作系统句柄。当然,您确实希望对象在GC'ed时处理其资源,如果没有
IDisposable
您就无法控制反向--
IDisposable
允许您在不再使用资源的时候清理资源。这使您能够为处理外部资源的问题设计更具确定性的解决方案,而不仅仅是单纯依赖GC所允许的解决方案。

Dispose
方法是考虑到托管内存以外的资源(非托管资源)仍然需要显式释放的事实而添加的;GC不是专门为它设计的

此外,
IDisposable
背后的机制独立于GC。当您遵循时,您可以通过使类可终结来选择性地将代码插入GC,但在实现
IDisposable
时不必这样做

处置与清理对象所持有的隐藏资源有关,而不是清理托管内存中对象的“外壳”。在调用
Dispose
之后,对象在尝试使用它时通常会抛出
ObjectDisposedException

回到您的代码,因为这两个变量实际上引用了同一个对象,
foo
变量将引用
using
块之后的已处理对象。因此,在使用
之后调用方法或访问
foo
的属性可能会引发异常:

var foo = GetFoo();

var anotherFoo = foo;

using(anotherFoo)
{
}

foo.doSomethingUseful(); // <<== This may throw ObjectDisposedException!
var foo=GetFoo();
var anotherFoo=foo;
使用(另一个)
{
}

foo.dosomethingusseve();// 将任何引用类型的每个变量、参数或其他存储位置视为持有一个“Object#291”形式的标记(但数字不同),并认为系统具有某种神奇的神秘能力,可以定位给定该形式标记的任何对象,并访问其字段或告诉它做些什么。调用某个对象的
Dispose
会告诉它“不再需要您的服务。一旦您使用此方法返回,您可能会在任何时候被放弃,而无需进一步通知。请随意使用此方法。”通常的预期是,如果对象已请求世界上任何地方的任何外部实体代表其执行某些操作,对象将告诉外部实体它不再需要这样做

假设对象#291是一个
文件
。它要求操作系统以独占方式访问磁盘上的文件,操作系统通过返回文件句柄来响应该请求;没有那个句柄,任何人都不能访问那个文件。对对象291调用
Dispose
,将指示它告诉操作系统它不再需要访问该文件,并且它将不再出于任何目的使用句柄。一旦发生这种情况,对象#291将不再能够访问磁盘上的文件,任何从对象#291读取数据的尝试都将失败


请注意——除了一个例外——对象#291的行为不会受到对其存在的引用数量的影响。只有当“强根引用”的数量降至零时,引用的数量才有意义。当这种情况发生时,对象将不再存在,除非它已请求放弃通知。如果某个对象已请求此类通知(通过实现名为
Finalize
)的方法),则在发现该对象第一次被放弃时,系统将确保该对象在其停止存在之前恢复足够长的时间以运行其
Finalize
方法。

谢谢。我理解我正在做的事情的语义,以及使用
结构的意义。只是确认垃圾收集器是否也检查引用计数作为标记要收集的对象的标准。我必须再次阅读Jeffrey Richter的书《通过C#或应用.NET Framework编程实现CLR》。@WaterCoolerv2,垃圾收集从不检查引用计数,因为.NET中没有引用计数。它检查是否存在任何线程或静态对象都无法引用的对象-是/否问题,而不是“多少?”问题。它与IDisposable的唯一联系是,如果某些内容已被垃圾收集,则无法再处理。(不过可以定稿)。谢谢你,@JonHanna。漂亮的回答。非常有洞察力。
Dispose
只是一种方法(按惯例用于资源管理),它与