【C#入門】usingステートメントで自動開放(Dispose、Closeの代替)

usingステートメントって使ってますか? usingステートメントを使うことで、例えばファイルの読み込みなどのリソースを開放する場合に使うDisposeメソッドなどの記述を省略することができます。

try-catch-finally文のfinallyブロックでDisposeメソッドを呼び出すのと同じ結果になるので、finallyブロックを記述する必要もないので便利です。

この記事では、usingステートメントについて

  • usingステートメントとは
  • try-catch文でDispose、Closeを使う場合
  • usingステートメントの使い方
  • 複数行のusingステートメントの使い方

など基本的な内容から、応用的な使い方の内容についても解説していきます。今回はusingステートメントについて、使い方をわかりやすく解説します!

目次

usingステートメントとは

usingステートメントとは、使い終わったらリソースを開放する必要がある場合に、自動的にDisposeメソッドを呼び出してくれる記述形式です。

Disposeメソッドとは、IDisposableインターフェースで宣言されているメソッドです。例えば、ファイルの入出力を扱うクラスのように使い終わったらリソースを開放する必要があるクラスは、このIDisposableインターフェースを実装してDisposeメソッドを使ってリソースを開放するようにしています。

このusingステートメントを使うと、try-catch-finally文のfinallyブロックを記述する必要がありません。Close処理やDispose処理を忘れてメモリリークが発生するのを防げるのでとても便利です。

名前空間の呼び出しとの違い

usingというと、名前空間の呼び出す場合にも記述しますので少し混乱するかもしれません。

コードを記述する時の

using System;

などです。今回お伝えしているusingステートメントはこの名前空間を呼び出すモノとは違います

try-catch文でDispose、Closeを使う場合

それではまずはtry-catch-finally文でDisposeメソッドを使ってリソースを開放する方法についてみていきましょう。

using System;
using System.IO;

namespace Sample
{
  class Sample
  {
    static void Main()
    {
      FileStream fs = null;
      try {
        fs = new FileStream("test.txt", FileMode.Open);
      } catch(FileNotFoundException e) {
        Console.WriteLine("ファイルが見つかりませんでした");
      }
      finally {
        if(fs != null) {
            fs.Dispose();
        }
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

ファイルが見つかりませんでした

このサンプルでは、FileStreamクラスのオブジェクトfsを生成しています。

FileStreamクラスはコンストラクタで指定したファイルが見つからなかった場合に、例外が発生しますので、catchブロックでその場合の例外処理を記述しています。

また、オブジェクトがnull以外の場合は処理が終わったらDisposeメソッドを使ってリソースを開放しています。この場合は、ファイルを開いた後の閉じる処理なので、Disposeメソッドの代わりにCloseメソッドでも構いません

usingステートメントの使い方

それでは、先ほどのサンプルコードをusingステートメントで記述してみましょう。

using System;
using System.IO;

namespace Sample
{
  class Sample
  {
    static void Main()
    {
      try {
        using (FileStream fs = new FileStream("test.txt", FileMode.Open)) {
          
        }
          
      } catch (FileNotFoundException e) {
        Console.WriteLine("ファイルが見つかりませんでした");
      }
      
      Console.ReadKey();
    }
  }
}

実行結果:

ファイルが見つかりませんでした

このサンプルコードでは、usingステートメントを使ってtry-catch-finally文のfinallブロックのDisposeメソッドの記述を省略しています。指定したファイルが見つからない例外に対してはtry-catch文で例外処理を行っています。

ちなみに、usingステートの「( )」(カッコ)内では最後に「;」(セミコロン)を記述しません。

複数行のusingステートメントの使い方

usingステートメントは複数行並べて記述することもネスト(入れ子)で記述することもできます。

サンプルコードで確認しましょう。

using System;
using System.IO;

namespace Sample
{
  class Sample
  {
    static void Main()
    {
      try {
        using (FileStream fs = new FileStream("test.txt", FileMode.Open)) {
          using(StreamReader sr = new StreamReader(fs)) {
            Console.WriteLine(sr.ReadToEnd());
          }
        }
          
      } catch (FileNotFoundException e) {
        Console.WriteLine("ファイルが見つかりませんでした");
      }
      
      Console.ReadKey();
    }
  }
}

このサンプルコードでは、FileStreamクラスのオブジェクトfsを生成しています。またそのオブジェクトfsを使って、StreamReaderクラスのオブジェクトsrを生成しています。

この場合、usingステートメントをネスト(入れ子)で使うことで、オブジェクトfsおよびsrをDisposeメソッドを使って開放する必要はありません。例えば、ネストの内側のusing(StreamReader sr = new StreamReader(fs))ブロック内でエラー処理が発生したとしても、オブジェクトsrはもちろんですが外側のオブジェクトfsもリソースが開放されます。

また、以下ののようにusingステートメントを2つ並べて記述しても、同じ処理が行われます。

using System;
using System.IO;

namespace Sample
{
  class Sample
  {
    static void Main()
    {
      try {
        using (FileStream fs = new FileStream("test.txt", FileMode.Open))
        using(StreamReader sr = new StreamReader(fs)) {
          Console.WriteLine(sr.ReadToEnd());
        }
      } catch (FileNotFoundException e) {
        Console.WriteLine("ファイルが見つかりませんでした");
      }
      
      Console.ReadKey();
    }
  }
}

まとめ

ここでは、usingステートメントについて説明しました。

usingステートメントはDisposeメソッドやCloseメソッドを使ってリソースを開放する必要がある場合に使うと、開放処理をし忘れることがなくなるので便利です。

C言語やJavaでは使われない記述形式ですので、慣れるまでは難しく感じるかもしれませんが、バグの発生を防止することができますので、使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
info@sss-lab.com

目次