C#に限らず、プログラミングをしていて、外部ファイルを開いたりコネクションを開いておいたりすることは多い。
そういった場合、後始末を忘れると、例えばファイルを開きっぱなしにしたりと、あちゃちゃ〜なコトになってしまう。
しかし、我々も人間。後始末をつい忘れてしまうこともある。C#でいうと、対象のオブジェクトのDispose()を呼び忘れたということだけれど、さすが至れり尽くせりのC#、そんなヒューマンエラーを防ぐ仕組み = usingステートメントを用意している。
後始末のためのインターフェース
usingステートメントの有り難みを紹介する前に、.Netが用意している後始末のためのインターフェースをおさらいしておこう。
前述の外部ファイルやアンマネージドリソースを開放するため、.NetはIDisposableというインターフェースを用意している。その内容はこちら。
1 2 3 4 5 6 7 8 9 10 11 |
namespace System { [ComVisible(true)] public interface IDisposable { // // Methods // void Dispose(); } } |
Dispose()を実装すればいいだけのシンプルなインターフェースで、実現クラスはこのメソッドの中で後始末をする。
具体的にはこう使う。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class NeedDisposeClass : IDisposable { public void Dispose() { Console.WriteLine("Dispose is done!"); } } var needDispose = new NeedDisposeClass(); // Do something. needDispose.Dispose(); |
IDisposableを実装したクラス NeedDisposeClass のインスタンスを使ったあと、Dispose()を呼んで後始末をするだけ。
ただ、needDisposeを作ってDispose()を呼ぶまでに例外が発生したりすると、Dispose()が呼ばれなくなってしまう。これを防ぐために、finallyを使う。
1 2 3 4 5 6 7 8 9 |
var needDispose = new NeedDisposeClass(); try { // Do something. } finally { needDispose.Dispose(); } |
tryの中で何が起ころうとfinallyに続く処理が実行されることが保証されているから、後片付けが実行されないことはない。安心安全のtry – finallyなわけですね。
usingは更にホッとする
ただ、finallyでもまだ不安は残る。要は、Dispose()を呼び忘れたら終わりなのだ。
作例では後始末が必要なインスタンスが一つだからいいものの、この類のものが2つ3つと出てくると危うくなってくる。
そこでC#が用意したのが using である。usingステートメントで宣言されたインスタンスは、usingを抜ける直前でDispose()を呼ばれるから、ヒューマンエラーのしようがない。その上、Dispose()が必要なインスタンスが複数の場合でもすっきりと書けるから嬉しい。具体的にはこう使う。
1 2 3 4 5 |
using (var needDispose1 = new NeedDisposeClass()) using (var needDispose2 = new NeedDisposeClass()) { // Do something. } |
try – finallyのときよりも行数が少なくなって、なんとなくスマートな感じもしてすこぶるイイ。後始末が必要なときは積極的にusingを使っていくべき。
IDisposableの実装方法
自作クラスでIDisposableを実装しないといけないシーン、これが意外とよくある。ただ、素直にDispose()を実装すればいいだけではないのが罠。実装は意外と面倒だから、こちらを参考にされたい。
[C#] イマイチ分かりにくいIDisposableの実装方法をまとめる。
変更に強いC#ソースを書く秘訣はこの本に載っています。