はじめに
DBとのコネクションのために利用するDbConnectionクラス。
このクラスをusing文で初期化したならば、Close処理を良しなにやってくれそうなので、Closeメソッドの記述は不要だと思っていたのですが、Closeメソッドを記述しているソースコードを散見しました。
例
using (DBEntities db = DbContext.CreateContext())
{
db.Database.Connection.Open();
// dbを使った処理
db.Database.Connection.Close(); // Closeを明記している
}
結局、要るのか要らないのか調査しました。
はじめに結論
DBコネクションを1度閉じてusingスコープ内で再OpenするならばCloseを書くべし。それ以外は不要(あってもなくても良い)。
その理由を以下に説明していきます。
理由
using文とは
そもそもusing文とは何ものなのかという話。
こちらの公式ドキュメントによると、
IDisposable オブジェクトの正しい使用を保証する簡易構文を提供します。
using文は、IDisposableインターフェースを実装したクラス(Disposeメソッドを実装している)でないと利用できません。
利用例を見てみます。
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
Font
クラスはIDisposableインターフェースを実装しているクラスなので、using文の中で初期化が可能です。
そして、コンパイラはこのusing文を以下のように展開します。
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
using文は、try {} finally {XXX.Dispose();}
をわざわざ書かなくてすむようにする糖衣構文ということです。
なので、using文で初期化されたインスタンスは必ずDisposeされることが保証されています。
DbConnectionクラスはIDisposableインターフェースを実装したComponentクラスを継承しているので、using文で初期化することで最後はDisposeされます。
Closeメソッドとは
こちらの公式ドキュメントによると、
you must explicitly close the connection by calling Close or Dispose, which are functionally equivalent.
functionally equivalentとあるように、 DbConnectionクラスにとっては、機能的にはCloseもDisposeもどちらも変わらない ということです。
なので、using文ではDisposeメソッドを必ず呼ぶので、結果、Closeメソッドは基本的に不要ということです。
しかし、1つ異なる点があります。
Closeメソッドは再度そのインスタンスを再Openできるのに、対し、Disposeメソッドは一度実行されたら、そのインスタンスにはアクセスできない
という点です。したがって「はじめに結論」での結論となります。
ではなぜCloseを書くのか
こちらの記事によると
It doesn't affect the behaviour of the code, but it does aid readability.
つまり、 可読性のため。(既存のコードに影響を与えないし) とのこと。複数のスコープがあるとどこでインスタンスがCloseされているのかがわかりにくくなるので、Closeを書くとよいということです。
おわりに
この記事の内容だけでは細かい理由が不十分だと思っています。追記するべき内容がわかったら適宜更新したいです。
補足
StreamReaderクラスについて
StreamReaderにも、Closeメソッドが用意されていますが、(Componentクラスを継承している)DbConnectionとは様子が違ってくるようです。こちらのQiitaの記事に詳細と議論が展開されています。
IDisposableインターフェースの実装
DbConnectionクラスはComponentクラスを継承しており、ComponentクラスでのDisposeメソッドでリソース管理の実装が記述されています。
独自にIDisposableインターフェースを実装したクラスを作成する必要があるとき、Disposeメソッドには、同様にリソース管理処理を実装する必要があります。
こちらの公式ドキュメントに具体的な実装方法が示されています。
この実装では、扱うリソースがGCの管理下かそうでないかを考慮して記述する必要があります。