Best Way to Cleanup Resources in C# through Using

It is a developer or programmer responsibility to cleanup the resources that have a Dispose() method in C#, not the system responsibility. In .Net, types which use unmanaged resources should be released explicitly by using Dispose() method of the IDisposable interface. If you don’t dispose of the resources, these will get freed by their finalizers when they get a chance to execute. Until finalizers executes, these resources will stay in memory and your application becomes slow.

You can cleanup the resource by calling Dispose() method as shown below. Here I am using Microsoft Visual Studio 2019 which was released on April 2nd, 2019.

class Program
{
        static void Main(string[] args)
        {
            object obj = new Employee(); 
 
            string str = obj as string;
 
            if (str == null)
            {
                Console.WriteLine("Casting failed through as operator");
            }
 
            Console.ReadLine();
        }
} 
 
class Employee
{
}

As shown above, we are disposing of two objects connection & command by calling Dispose() method. Above code works fine and cleanup the objects from memory if there is no exception. For example, if some error occurs before calling Dispose() method, then objects stay in memory until finalizers execute.

We can cleanup the resource even if an exception occurs by using the “using” statement as below. 

private void GetData()
{
            using (SqlConnection connection = new SqlConnection("Server=DBServer;Database=Company;Trusted_Connection=True;"))
            {
                using (SqlCommand command = new SqlCommand("SELECT * FROM Employee", connection))
                {
                    connection.Open();

                    SqlDataReader dataReader = command.ExecuteReader();
                }
            }
}

Through using statement, we can ensure that objects will get dispose properly even if some exception occurs by generating try/finally block around object that being allocated. 

 private void GetData()
 {
            using (SqlConnection connection = new SqlConnection("Server=DBServer;Database=Company;Trusted_Connection=True;"))
            {
                connection.Open();
            }
}

The above code will convert into try/finally block as below. 

private void GetData()
{
            SqlConnection connection = null;
            try
            {
                connection = new SqlConnection("Server=DBServer;Database=Company;Trusted_Connection=True;");
                connection.Open();
            }
            finally
            {
                connection.Dispose();
            }
}

If we use two using statements, code will generate two try/finally blocks as shown below. 

 private void GetData()
 {
            SqlConnection connection = null;
            SqlCommand command = null;
            try
            {
                connection = new SqlConnection("Server=DBServer;Database=Company;Trusted_Connection=True;");
                command = new SqlCommand("SELECT * FROM Employee", connection);

                try
                {
                    connection.Open();
                    SqlDataReader dataReader = command.ExecuteReader();
                }
                finally
                {
                    command.Dispose();
                }
            }
            finally
            {
                connection.Dispose();
            }
 }

It is not advisable to use multiple using statements in the same method as it generates multiple try/finally blocks. You can write single try/finally block instead of multiple using statements like below.

private void GetData()
{
            SqlConnection connection = null;
            SqlCommand command = null;

            try
            {
                connection = new SqlConnection("Server=DBServer;Database=Company;Trusted_Connection=True;");
                command = new SqlCommand("SELECT * FROM Employee", connection); 

                connection.Open();

                SqlDataReader dataReader = command.ExecuteReader();
            }
            finally
            {
                command.Dispose();
                connection.Dispose();
            }
}

You cannot use using statement on any type that does not support the IDisposable interface. If you try to use using statement on non-disposable types, C# generates compile-time errors as shown below.

Whenever you are working with connection object, use Dispose() method instead of just calling the Close() method because Dispose() method will do more than the Close() method does. Dispose of () method will inform the garbage collector that specific object no longer requires to be finalized and also calls GC.SuppressFinalize() method where Close() will not perform these tasks.