使用`using(...)`有效无用和/或低效?

时间:2010-02-13 23:06:31

标签: c# idisposable using

以下代码是否使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();
    }
}
  

输出:SuperDisposable

我对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)处有一个断点),其中false被传递给方法,因此必须在此处妥善处理资源。无论如何,班级仍然活着,但你肯定是在为异常做好准备。答案让我更好奇......

4 个答案:

答案 0 :(得分:11)

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

using语句的正确场景是,当您想要初始化资源,对其执行某些操作,然后销毁它并忘记它时;例如:

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

如果要在使用后保留对象,则不应将其丢弃,因此不应使用using语句。

答案 1 :(得分:2)

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

IDisposable接口表示某种类型管理某种资源。存在Dispose方法,允许您处理实例使用的资源,而不必等待垃圾收集以及终结器释放的资源。

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

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