澄清IDisposable界面的一些事情。调用Dispose后,实例(必须)等于null吗?

时间:2010-09-06 06:54:38

标签: c# .net

我有一个实现IDisposable接口的类。

using System;

class A : IDisposable
{
        public void Dispose()
        {
            Stop(); // some actions to stop internal threads

            this = null;
        }
}

为什么我不能在Dispose方法中指定this = null?我知道'这'是只读的。

例如:

A a = new A();
a.Run();
// ...
a.Dispose();
// i want in this line a = null

我认为IDisposable和Dispose方法保证在调用Dispose()之后,类A的实例将等于null。但事实并非如此。

4 个答案:

答案 0 :(得分:3)

不,就{CL}而言,Dispose只是一种方法,就像任何其他方法一样。 C#通过using语句支持它(并且foreach并且迭代器被释放),但除此之外没有任何意义。特别是,它不直接与垃圾收集器交互,或影响引用已处置对象的任何变量。 (IDisposable的某些实现也可能具有调用Dispose的终结器,但它们在逻辑上是不同的概念。)

请注意,对象在处理后不一定无法使用。例如,处置MemoryStream并不会清除内存中的数据 - 之后使用ToArray仍可以使用。

确实,the documentation for IDisposable明确地谈到了它被用于重置对象以供重用的可能性:

  

使用此方法关闭或释放非托管资源,例如文件,流和   由实现此接口的类的实例持有的句柄。按照惯例,   此方法用于与释放对象持有的资源相关的所有任务,或   准备重新使用的对象。

答案 1 :(得分:2)

只是添加到已经说过的内容:

重要的是要意识到有对象,并且有引用(变量),而这些不是同一个东西。< / p>

当你写var a = new object();时,你正在做两件事:

  1. 创建新的object实例。此实例没有“名称” - 只是内存中的一个位置。就是这样。但是,我们有一些东西可以称之为“鲍勃。”
  2. 声明变量 a引用刚刚创建的object
  3. 现在,当您编写a = null;时,您正在向Bob执行 nothing 。您正在将a更改为引用,而不是Bob,null,或者换句话说,“没有对象”。因此,您无法再使用a访问“Bob”。

    这是否意味着现在Bob不存在?不,鲍勃仍然在他所在的地方。

    考虑这个(基本上是the scenario Henk mentioned):

    var a = new object(); // Again, we're calling this object Bob.
    object b = a;
    

    现在,b是另一个变量,就像a一样。就像a一样,b引用了Bob。但同样,就像a一样,写b = null;对鲍勃没有任何作用。它只是更改b,以便它不再指向对象。

    这是我要去的地方。你似乎一直认为这样做:

    a.Dispose();
    

    ......不知何故也这样做了:

    a = null;
    

    ......这在某种程度上等同于这样做:

    <强> Bob = null; // now Bob is no object?

    但如果是这种情况,那么b(上图)现在会指向无对象,即使它从未设置为null!< /强>

    无论如何,根据我上面的解释,希望很明显这不是CLR的工作原理。正如Jon指出的那样,IDisposable接口实际上与释放的内存无关。它是关于释放共享资源。它没有 - 不能 - 从内存中删除对象,就好像它一样,然后我们会有上面描述的行为(引用突然变得无效)。

    我知道这只与你关于IDisposable的具体问题松散地相关,但我感觉这个问题来自对变量和对象之间关系的误解;所以我想让这种关系更加清晰。

答案 2 :(得分:1)

这是不可能的,但也没有用。

在以下位置考虑b

A b = a; // alias
a.Dispose();
// i want in this line a = null

这不是一个真正的问题,仍然有一个ab引用的对象。它只是将其内部状态更改为“已关闭”。一些IDisposable类有一个bool IsDisposed成员,您可以在Dispose()

之后安全地调用它

答案 3 :(得分:1)

您的假设不正确。 Dispose()不会回收实例,也不会影响引用。

这是一种实用方法,它得到了框架/编译器的特别关注,可以让您轻松清理GC未处理的资源。除此之外,它只是一种常规方法。调用方法不应该影响引用本身。

The recommendation用于实施Dispose()具体说明

  

帮助确保资源   总是妥善清理,a   处理方法应该是可调用的   多次而不抛弃   异常。