Managing Resources with Using in C#

mirzaleka

Mirza Leka

Posted on July 14, 2024

Managing Resources with Using in C#

The using statement is a poweful utility for automatic disposal of unused resources.

The base implementation works like this:



        using (var ch = new CustomHandler())
        {
            /* Do something with ch */
        }


Enter fullscreen mode Exit fullscreen mode

The using statement is useful for preventing memory leaks by handling unmanaged resources like:

  • Close files that are no longer being used
  • Close database connections
  • Handle HTTP Client termination, etc.

In order to use the using statement for a given class, the class must implement the IDisposable interface:



class CustomHandler : IDisposable
{
    public void SayHello()
    {
        Console.WriteLine("Hello World!");
    }

    // coming from IDisposable
    public void Dispose()
    {
        Console.WriteLine("Handled dispose!");
    }
}


Enter fullscreen mode Exit fullscreen mode

The automatic disposal can be verified by throwing an exception in SayHello() method.



class CustomHandler : IDisposable
{
    public void SayHello()
    {
        throw new Exception("Something went wrong!");
    }

    public void Dispose()
    {
        Console.WriteLine("Handled dispose!");
    }
}


Enter fullscreen mode Exit fullscreen mode

I created a new class Main that creates an instance of CustomHandler().

Without Using

First test, no using.



public class Main
{
    public void LearnUsing()
    {
        var ch = new CustomHandler();
        ch.SayHello();
    }

}

var m = new Main();
m.LearnUsing();


Enter fullscreen mode Exit fullscreen mode

The exception is thrown and the process is terminated as expected, but no resources were disposed.



Unhandled exception. System.Exception: Something went wrong!

Process finished.


Enter fullscreen mode Exit fullscreen mode

With Using



public class Main
{
    public void LearnUsing()
    {
        using (var ch = new CustomHandler())
        {
            ch.SayHello();
        }
    }

}

var m = new Main();
m.LearnUsing();



Enter fullscreen mode Exit fullscreen mode

This time around the resources are disposed sucessfully.



Unhandled exception. System.Exception: Something went wrong!

Handled dispose! <<<<<<<

Process finished.


Enter fullscreen mode Exit fullscreen mode

Manual Disposal

By this point you probably asked yourself a question, why not use Try-Catch-Finally block? That works too, but Try-Catch doesn't dispose resources. It only handles errors.

In order to dispose resources in Try-Catch you'd need to manually call the dispose method:



        var ch = new CustomHandler();
        try
        {
            ch.SayHello();
        }
        catch (Exception ex)
        {
            /* Handle exception */
        }
        finally
        {
            // Manual disposal
            ch.Dispose();

            // I'm using finally here because it will be invoked
            // regardless if SayHello() is a success or an exception
        }


Enter fullscreen mode Exit fullscreen mode

The using statement on the other hand calls the Dispose() method automatically.

Using in Existing Classes

As mentioned, any class that implements the IDisposable interface can be used within the using block.

FileStream



        using (FileStream fs = new FileStream("greetings.txt", FileMode.Open))
        {
            /* Write to file */
        }


Enter fullscreen mode Exit fullscreen mode

HTTPClient



    public async Task LearnUsing()
    {
        using (var httpClient = new HttpClient())
        {
            var response = await httpClient.GetAsync("/api/getData");

            if (response.IsSuccessStatusCode)
            {
                /* Handle response */
            }
        }
    }


Enter fullscreen mode Exit fullscreen mode

Just make sure you prefix the call to LearnUsing() with await keyword as it now a Task.



await m.LearnUsing()


Enter fullscreen mode Exit fullscreen mode

SQL Connection

The using statement is also used when executing database queries without using any frameworks. To get started, install System.Data.SqlClient package via nuget package manager and import it as a dependency.

nuget-pm

Then setup a connection string to your DB. For this I created a local DB via SQL Server.

SSMS

To connect to your local DB set up a connection string in your C# application.



        string connectionString = "Server=<Server-Name>;Database=<Database-Name>;Integrated Security=True;";
// or in my case
        string connectionString = "Server=DESKTOP-F5;Database=Games;Integrated Security=True;";


Enter fullscreen mode Exit fullscreen mode

Now using a combination of using statements:

  • Establish a connection with the database (SqlConnection)
  • Excute SQL Query (SqlCommand)
  • Read the response from the Table (SqlDataReader)

Here you can see how to nest the using statements.



        string connectionString = "Server=DESKTOP-F5;Database=Games;Integrated Security=True;";

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            try
            {

                await connection.OpenAsync();

                string sqlQuery = "SELECT * FROM Game_Types";

                using (SqlCommand command = new SqlCommand(sqlQuery, connection))
                {
                    using (SqlDataReader reader = await command.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                        {
                            Console.WriteLine(reader["Title"]); // Multiplayer 
                            // prints row data for each iteration
                        }
                    }
                }

            }
            catch (SqlException ex)
            {
                Console.WriteLine(ex.Message);
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }


Enter fullscreen mode Exit fullscreen mode

Note: If you're using an Entity Framework, the queries do not need to be wrapped with using. The DbContext class automatically disposes the resources.

For immediate disposal, the using statement can also be used inline (without curly brackets).



using (var fs = new FileStream("my-file.txt", FileMode.Open))
    Console.WriteLine("File open!");


Enter fullscreen mode Exit fullscreen mode

That's all I have for today. Don't forget to hit the follow button. Also, follow me on Twitter to stay up to date with my upcoming content.

Bye for now 👋

💖 💪 🙅 🚩
mirzaleka
Mirza Leka

Posted on July 14, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related