from http://garicchi.hatenablog.jp/entry/2014/09/14/200000
IDisposable
IDisposableは簡単に言うと、「実装すると、Disposeメソッドを実行することによってリソースを破棄してくれることを保証するインターフェース」です。
ようするにクラスがもっているリソースをDispose
メソッドによって破棄する、
C++のdeleteと似たところがあります。
じゃあ
IDisposableインターフェース実装する必要ないやん!ってなりますが
C#には.Netの
ガベージコレクションが解放してくれないリソースがあるのです。
マネージリソースとアンマネージリソース
.Netでは、
C#で作ったクラスなどは
マネージリソースとよび、.Netの
ガベージコレクションによってメモリがたりなくなりかつオブジェクトがどこからも参照されなくなると破棄されます。
いっぽう、ファイルの入出力なのでつかうファイルは
アンマネージリソースとよび、.Netの
ガベージコレクションによって破棄されません。
IDisposableインターフェースは、このようなアンマネージリソースを破棄するための機能を実装するインターフェースです。
たとえば、StreamReaderなどのクラスを使うとき、このような形になります。 Close
メソッドが呼ばれた時、ファイルのアンマネージリソースは解放されます。
static void Main(string[] args)
{
try{
StreamReader reader = new StreamReader("hoge.txt");
string text=reader.ReadToEnd();
reader.Close();
}catch(Exception){
}
}
ではreader.Closeを呼ぶ前に例外が発生したらどうなるでしょうか。
static void Main(string[] args)
{
try{
StreamReader reader = new StreamReader("hoge.txt");
string text=reader.ReadToEnd();
reader.Close();
}catch(Exception){
}
}
Close
メソッドがよばれませんね。すると永久に
hoge.txtのアンマネージリソースは解放されません。 これではダメなのでfinallyを使ってCloseを強制的に呼び出します。
static void Main(string[] args)
{
try{
StreamReader reader = new StreamReader("hoge.txt");
string text=reader.ReadToEnd();
}catch(Exception){
}finally{
reader.Close();
}
}
さらにこれでもreaderがnullだった場合、nullpointerExceptionが出てしまいます。
このように非常にめんどくさいことになるのでC#ではIDisposableを実装することによってusing文をつかった統一的なアンマネージリソース処理方法があります。
using
C#では先程の処理をusingを使ってこんな感じにかくことができます。
using (StreamReader reader = new StreamReader("hoge.txt"))
{
string text = reader.ReadToEnd();
}
まったく後処理がされていませんが、StreamReaderはIDisposableインターフェースを実装しているので
コンパイル時にこんな感じに最適化されます。
StreamReader reader=null;
try
{
reader= new StreamReader("hoge.txt");
string text = reader.ReadToEnd();
}
catch (Exception e)
{
}
finally
{
if (reader != null)
reader.Dispose();
}
これでどこで例外が起きようが確実にDispose
メソッドを実行してアンマネージリソースを解放することができます。
なのでIDisposableインターフェースを実装しているクラスを使うときは、なるべくusing文法を使うことが推奨されています。
IDisposableを実装してみる
ではIDisposableを実装したDisposableStreamReaderというクラスを作ってみます。
public class DisposableStreamReader:IDisposable
{
StreamReader reader = null;
public DisposableStreamReader()
{
reader = new StreamReader("hoge.txt");
}
public string ReadAll()
{
return reader.ReadToEnd();
}
public void Dispose()
{
reader.Dispose();
}
}
IDisposableインターフェースが実装を保証するのはDispose
メソッドです。ここでアンマネージリソースを解放します。
これを使うときはこんなかんじでusing文を使うことが可能になります。
static void Main(string[] args)
{
using(DisposableStreamReader reader=new DisposableStreamReader())
{
string str= reader.ReadAll();
}
}
まとめ
- .Netにはマネージリソースとアンマネージリソースがある
- IDisposableはDisposeメソッドでアンマネージリソースを解放することを保証する
- IDisposableインターフェースを実装することによってusing文をつかうことができる
留言
張貼留言