C#初心者のための基礎!Disposeとusingの意味と使い方を解説#24

当サイトではアフィリエイト広告を利用しています。

C#初級プログラミング

Disposeとは?

Disposeとは、インスタンスのリソースを解放するときに呼び出すメソッドです。IDisposableというインタフェースを実装しているクラスには必ず実装されているメソッドになります。リソースの解放とは、アプリケーションが動作中に確保していくメモリを解放することです。C#でintと宣言されれば4バイトのメモリが確保されます。そのメモリをずっと使用したままだと、パソコンのメモリが食いつぶされて、動作できなくなってしまうので、通常は不要になったタイミングでメモリというのは解放される必要があります。

C#ではメモリの解放を自動的にしてくれます。だから通常は意識しなくても不要になったメモリは解放されていきます。しかし、アプリケーションの外側にアクセスした場合は話が変わってきます。例えばデータベースにアクセスしたり、ファイルにアクセスした場合です。それらのファイルはアプリケーションの外側に存在しているため、ファイルを開いたままとかにすると、ずっとリソースが解放されずに残ってしまいます。そこで、外部のリソースを使用したら、使い終わったことを明示的に意思表示する必要があります。そのためのメソッドがDisposeになります。

リソースの解放が必要なインスタンスの見分け方

リソースの解放が必要か不要かは、インスタンスにドットを付けてDisposeメソッドが存在するかで確認できます。または、インスタンスのクラスの定義にIDisposableが実装されているかどうかでも確認できます。Disposeを実装しているクラスを使っている場合は必ずDisposeを呼び出しましょう。

Disposeの呼び方

SqlConnection connection = new SqlConnection();
//何らかの処理・・・
connection.Dispose();

このように、通常のメソッドと同じようにDisposeメソッドを呼び出すことができますが、上記の記述では、SqlConnectionのインスタンスを生成後、処理中にエラーが生じた場合はDispose()が呼ばれない可能性があります、そこでfinallyキーワードを使って、必ずDispose()が実行されるように記述することができます。

SqlConnection connection = new SqlConnection();

try
{
    //処理
}
catch (Exception ex)
{

}
finally
{
    connection.Dispose();
}

これで、処理中にエラーが発生しても必ずDispose()が呼び出されます。

usingとは?

usingを使うとfinally キーワードを使ってDisposeをするのと同等の動作を手軽に記述することができます。

using (SqlConnection connection = new SqlConnection())
{
}

このように記述すると、中確固を通り抜けると同時にDispose()の実行が保証されます。こう書いたほうがtryステートメントを書く必要がないため、見た目もわかりやすく、確実にリソースの解放ができるため、この書き方が推奨されています。

usingの使用が推奨されてはいますが、usingが使えるのは、インスタンスの生成と破棄が一つのメソッド内で行われる場合のみです。クラスの中にフィールドとして宣言されている変数に対してusingを記述することはできません。その場合はDispose()を呼び出す必要があります。

フィールドの変数でDisposeが必要な場合

クラスの中に宣言されているフィールドでDisposeが必要な場合はDisposeをどこに記述すればよいでしょうか?

メソッド内で完結する変数と異なり、変数が使い終わるタイミングがわからないため、クラス自体でDisposeを呼び出すタイミングはわかりません。そのため、外部から使用しているクラスにリソースの破棄をしてもらう必要があります。

外部からリソースを破棄してもらうには、そのクラス自体にIDisposableを実装する必要があります。クラスにIDisposableを実装するとDisposeの実装が強制されます。Disposeを生成し、その名から、そのクラスでDisposeが必要な変数をすべてDisposeします。

フィールド変数をDisposeする例

次のDatabaseクラスでは、IDisposableを実装し、プライベート変数である_adapter変数を自身のDisposeメソッドで_adapter.Dispose()とすることで解放しています。Databaseクラスを使う側では必ずDisposeもしくはusingキーワードを使う必要があります。

using System;
using System.Data.SqlClient;

namespace CS24
{
    public class Database : IDisposable
    {
        private SqlDataAdapter _adapter = new SqlDataAdapter();
        public Database()
        {
        }

        public void Insert()
        {
            using (SqlConnection connection = new SqlConnection())
            using (SqlCommand command = new SqlCommand("select * from xxx", connection))
            {
                //処理
            }
        }

        public void Cancel()
        {
            _adapter.SelectCommand.Cancel();
        }

        public void Dispose()
        {
            if(_adapter != null)
            {
                _adapter.Dispose();
            }
        }
    }
}

Databaseクラスを使う側

using System.Windows.Forms;

namespace CS24
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            using (Database d = new Database())
            {

            }
        }
    }
}

補足

usingキーワードは2種類あり、今回紹介した内容以外にも、クラスの上部に書かれているusingが存在します。クラス上部に書かれているusingは、ネームスペースを省略してコーディングするためのモノなので、今回のリソースの解放とは用途が異なります。