LoginSignup
14
24

More than 5 years have passed since last update.

using文で初期化したDbConnection、Closeを書くべき?書かなくていい?

Last updated at Posted at 2017-07-17

はじめに

DBとのコネクションのために利用するDbConnectionクラス。

このクラスをusing文で初期化したならば、Close処理を良しなにやってくれそうなので、Closeメソッドの記述は不要だと思っていたのですが、Closeメソッドを記述しているソースコードを散見しました。

sample-dbclose.cs
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メソッドを実装している)でないと利用できません。

利用例を見てみます。

sample-using.cs
using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

FontクラスはIDisposableインターフェースを実装しているクラスなので、using文の中で初期化が可能です。

そして、コンパイラはこのusing文を以下のように展開します。

sample-using-extended.cs
{
  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の管理下かそうでないかを考慮して記述する必要があります。

参考

14
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
24