Garbage Collection (3), C# using statement --- Language support for Dispose

In computer science, garbage collection (GC) is a form of automatic memory management. The garbage collector attempts to reclaim memory that was allocated by the program but is no longer referenced; such memory is called garbage. Garbage collection was invented by American computer scientist John McCarthy around 1959 to simplify manual memory management in Lisp.

This series of articles discuss the Garbage Collection in .NET.

A - Introduction

The using statement in C# and the Using statement in Visual Basic simplify the code that you must write to create and clean up an object (by Dispose pattern). The using statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object.

The content of this article will be

  • A - Introduction
  • B - Sample Code
  • C - try/finally Block
  • D - using Block
  • E - using Declaration

B - Sample Code

using System;

namespace TestUsing
{
    public class Thing : IDisposable
    {
        private string name;
        public Thing(string name) { this.name = name; }
        override public string ToString() 
        { return String.Format("Thing : " +name); }
 
        ~Thing() 
        { 
            Dispose();
            Console.WriteLine("~Thing: " +name); 
        }
 
        public void Dispose()
        {
            Console.WriteLine("Dispose: " +name);
            //GC.SuppressFinalize(this);
        }
    }

    class TestUsingApp
    {
        [STAThread]
        static void Main(string[] args)
        {
            Thing t1 = new Thing("Ethel");
            try
            {
                Console.WriteLine(t1);
            }
            finally
            {
                if (t1 != null)
                    ((IDisposable)t1).Dispose();
            }
 
            using (Thing t2 = new Thing("JimBob")) 
            {
                Console.WriteLine(t2);
            }

            Console.WriteLine("\nForcing a Collection");
 
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
}

C - try/finally Block

Using conventional coding constructs, the best way to ensure that an object's lifetime is controlled and resources are cleaned up deterministically is by enclosing the object in a try and finally block, such as in our code:

The workflow is like this --- starting from Line 30:

D - using Block

The pattern above is so standard that the C# language supports it through the use of the using statement. The previous code ith a try and finally block can be rewritten as follows:

The workflow is like this --- starting from Line 41:

The using statement requires that the class implement IDisposable. We can look at the CIL by Visual Studio command ildasm for this statement that it does in fact expand to the equivalent try...finally block.

where IL_0029 is the code Line 41 starting the using block; while IL_0034 to IL_0049 is the equivalent try...finally block in IL.

E - using Declaration

After C# version 8, You can also use a using declaration that doesn't require braces:

When declared in a using declaration, a local variable is disposed at the end of the scope in which it's declared. In the preceding example, disposal happens at the end of a method (see the different workflow).

Note

using declaration, you must use the .NET Core,

otherwise, say, you use .NET 4.8, it will not work, Get words.

References