こんにちは、リバティエンジニア[?]のFUNAです。 現役エンジニアとしてアプリケーション開発やWeb制作、SEOやブログ運営をしています。
今回は自動でインスタンスを解放してくれる便利な機能「usingステートメント」について解説します。
目次
【C#】usingステートメントとは?
ファイルの読み込みなどのリソースを開放する際に、Disposeメソッドなどを使うことがあると思います。
でも実際Disposeの実装って地味に面倒ですよね。。
ですが、今回紹介するusingステートメントを使うとそんな面倒な記述を省略することができます。
try-catch-finally文のfinallyブロックでDisposeメソッドを呼び出すのと同じ結果になるので、finallyブロックを記述する必要もないので便利ですよ。
【C#】例外処理でアプリケーションを安全に(try-catch-finally)
名前空間を呼び出す時に使う「using」との違い
みなさん「using」と聞くと、名前空間を呼び出す際の記述を思い浮かべると思います。
using System;
ですが、今回紹介する「using」は上記のものとは異なるので注意が必要です。
【C#】try-catch文で自分でDisposeやCloseを行う
まずは、自分でリソースの開放をする場合を見ていきます。
今回出す例文ではtry-catch文を使ったやり方をご紹介します。
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メソッドでも代用できます。
【C#】usingステートメントの使い方
では上記のtry-catch文で記述したものを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();
}
}
}
実行結果 :
ファイルが見つかりませんでした。
このように、usingステートメントを使ってtry-catch-finally文のfinalyブロックのDisposeメソッドの記述を省略することができます。指定したファイルが見つからない例外に対してはtry-catch文で例外処理を行っています。
【C#】複数行で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ステートメントはc言語などの他の言語ではないような記述なので、少し難しく思うかもしれません。
ですが、1度やってしまえば簡単で記述もシンプルなので覚えて損はないものです。
リソースの開放忘れで例外が発生するなんて、中堅以上のプログラマになってくると絶対にしてはいけない(考慮しなければならない)ことなのでしっかりと今日覚えておきましょう。