[C#]Usingの目的と使い方

Usingを使えという記事に結構アクセスがあるので、もうちょっと基本的なところから解説をしたい。

Usingを使うと何が嬉しいのか

リソースの開放を確実に行える。ファイルを開きっぱなしで閉じないとか、長い間起動しているとだんだんメモリを食うとか、そういうバグを減らせる。

どうやって使うのか

基本的には閉じなければならないリソースのインスタンスを作るときにusingで囲ってあげればいい。

using (FileStream fs = new FileStream("./aho.txt", FileMode.Open, FileAccess.Read))
{
    // なんかの処理
}

そういうリソースが複数ある時はusingをまとめて書ける。

using (FileStream fs = new FileStream("./aho.txt", FileMode.Open, FileAccess.Read))
using (StreamReader sr= new StreamReader(fs, Encoding.UTF8))
{
    // なにかの処理
}

これでどういう動作になるかというと、usingに続くステートメントブロック(中括弧{}で囲んだ行)から抜けるときは、usingでインスタンス化されたオブジェクトが必ず解放される。例外が発生しても、gotoで飛んでも、returnしても解放される。だから、「例外発生した時はclose呼ばないから解放されない」なんてバグが発生しない。

ステートメントブロックを抜けると必ず解放されるので、close()とかflush()とかを明示的に呼び出す必要はない。

すげー便利!!良い!!

どういうクラスのオブジェクトがusingできるのか

.NET標準フレームワークに備わっていて、closeとかflushとか必要なものは何でもできます。できるかどうかわからない場合、とりあえず書けばVisual Studioがすぐにエラーを出してくれます。よくわからん場合はとにかく書いてみましょう。

もうちょい詳しく

using ステートメント (C# リファレンス) - MSDN

using節でインスタンス化できるオブジェクトはIDisposableインタフェースを実装したものだけです。using節で宣言された変数のスコープはそれに続くステートメントブロック内となり、スコープを抜けると必ずIDisposable.Dispose()が呼ばれます。そういう機能です。

なので、Dispose()の中でちゃんとした終了処理が実装されていないと、この機能は役に立ちません。標準フレームワークに搭載されているクラス群は大丈夫でしょうが、自分でIDisposableインタフェースを実装するときは注意しましょう。

応用

usingを応用して「スコープを抜けたときにCommitされていなければ勝手にRollbackしてくれる自作のトランザクションスコープ」なんかを作れます。(気の利いたO/Rマッパとかフレームワークを使えばこのくらいは勝手にやってくれるんですが・・・。)