4

以下代码是否使using(...)功能/目的无关紧要?
它会导致GC性能不足吗?

class Program
{
    static Dictionary<string , DisposableClass> Disposables
    {
        get
        {
            if (disposables == null)
                disposables = new Dictionary<string , DisposableClass>();

            return disposables;
        }
    }

    static Dictionary<string , DisposableClass> disposables;

    static void Main(string[] args)
    {
        DisposableClass disposable;
        using (disposable = new DisposableClass())
        {
            //  do some work
            disposable.Name = "SuperDisposable";
            Disposables["uniqueID" + Disposables.Count] = disposable;
        }

        Console.WriteLine("Output: " + Disposables["uniqueID0"].Name);

        Console.ReadLine();
    }
}

class DisposableClass : IDisposable
{
    internal string Name
    {
        get { return myName; }
        set { myName = value; }
    }

    private string myName;

    public void Dispose( )
    {
        //throw new NotImplementedException();
    }
}

输出:超级一次性

我对using(...)功能的理解是立即强制处置DisposableClass. 然而在代码块中,我们将类添加到字典集合中。我的理解是,一个类本质上是一个引用类型。所以我的实验是看看以这种方式添加到集合中的一次性对象会发生什么。

在这种情况下DisposableClass仍然是相当活跃的。类是一种引用类型 - 所以我的假设变成了集合不仅仅是引用这种类型,而是确实将类作为一个值。但是,这也没有任何意义。

那么到底发生了什么?

编辑:修改后的代码,输出证明对象没有死,正如一些答案所暗示的那样。

第二次编辑:当我经历了更多代码时,这归结为:

    public void Dispose( )
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool dispose)
    {
        if (!isDisposed)
        {
            if (dispose)
            {
                // clean up managed objects
            }

            //  clean up unmanaged objects
            isDisposed = true;
        }
    }

    ~DisposableClass( )
    { Dispose(false); }

单步执行代码(在 处有一个断点private void Dispose(bool dispose)),将 wherefalse传递给方法,因此必须在此处正确处理资源。无论如何,这门课还活着,但你肯定是在为例外做好准备。答案让我更加好奇...

4

4 回答 4

11

处置一个对象并不会破坏它;它只是告诉它清理它使用的任何非托管资源,因为它们不再需要。在您的示例中,您正在创建一个一次性对象,分配给字典,然后只是告诉它删除一些资源。

using语句的正确场景是当你想要初始化一个资源,用它做某事,然后销毁它并忘记它;例如:

using (var stream = new FileStream("some-file.txt"))
using (var reader = new StreamReader(stream))
{
    Console.Write(reader.ReadToEnd());
}

如果您想在使用后保留该对象,则不应处置它,因此using不应使用语句。

于 2010-02-13T23:11:08.920 回答
2

在这种情况下,您不应该使用using块,因为在块完成后您需要对象。只有在对象的生命周期有明确的起点和终点时才使用它。

于 2010-02-13T23:09:11.100 回答
2

重要的是要记住 IDisposable 虽然是一个稍微特殊的接口,但它仍然是一个接口。当 using 块退出时,它会在您的对象上调用 Dispose()。而已。您的引用仍然有效,如果您的 Dispose 方法不执行任何操作,您的对象将完全不受影响。如果您不跟踪处置并显式抛出异常,那么在那之后您将不会收到任何异常,因为 .NET 中没有固有的处置状态。

于 2010-02-14T00:00:21.440 回答
1

IDisposable接口表明一个类型管理某种资源。该Dispose方法的存在是为了让您处理实例使用的资源,而不必等待垃圾收集发生和资源被终结器释放。

在您的示例中,字典仍然包含对一次性类的引用,但该实例将在块的末尾被using释放。随后尝试调用实例上的方法现在可能会抛出ObjectDisposedExceptionor InvalidOperationException,以指示实例不再处于“工作”状态。

IDisposable不要将处理 an与释放实例占用的内存或在其上调用任何垃圾收集例程相混淆。该实例像任何其他实例一样由垃圾收集器跟踪和管理,只有在垃圾收集器决定它时才被释放。

于 2010-02-13T23:11:29.507 回答