都内で働くSEの技術的なひとりごと / Technical soliloquy of System Engineer working in Tokyo

都内でサラリーマンやってます。SQL Server を中心とした (2023年からは Azure も。) マイクロソフト系(たまに、OSS系などマイクロソフト以外の技術も...)の技術的なことについて書いています。日々の仕事の中で、気になったことを技術要素関係なく気まぐれに選んでいるので記事内容は開発言語、インフラ等ばらばらです。なお、当ブログで発信、発言は私個人のものであり、所属する組織、企業、団体等とは何のかかわりもございません。ブログの内容もきちんと検証して使用してください。英語の勉強のため、英語の

ソースコードを読んでいて Dispose の扱いについて少し気になったので記事かいてみた

 C# のソースコードを読む機会が久々にあったので、プログラミング 関連の記事書いてみます。最近、DBMS ばっかりだったので、久しぶりにプログラム触ると楽しいですね。( 自分の本業は、プログラムだといまだに思ってます!)

 楽しいのはさておき、今回は取り扱うお題は、『 Dispose 』です。下記のコードを元に説明をします。※コードは MSDN から引用しています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class BaseClass : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;

// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed) return;

if (disposing) {
// Free any other managed objects here.
//
}

// Free any unmanaged objects here.
//
disposed = true;
}
~BaseClass()
{
Dispose(false);
}
}

 クラスを使用する側が Dispose メソッドを絶対呼び出すとは限らないので、デストラクタを用意します。但し、その場合二回解放処理が走ってしまうため、GC.SuppressFinalize を呼び出して、二度解放処理が走ってしまうのを抑止します。

 しかし、呼び出し側で Dispose を呼び出さないで、ファイナライザーにお世話になるのはあまりよろしくないので、上記ソースの27行目~30行目を下記のように一工夫しましょう。( いやがらせ?いや、Dispose 呼ばない人が悪い...はず。使ったものが必要なくなったらきちんと消すのが基本です(`・ω・´) )

1
2
3
4
5
6
~BaseClass()
{
//ここにAssert or ログを仕込む。
System.Diagnostics.Debug.Assert(false,"ファイナライザーにいつも頼っちゃダメです!");
Dispose(false);
}

 下記のようなソースを試してみると動きがよくわかります。簡単な WindowsFormのボタンクリックイベントなどに組み込みます。

1
2
3
4
5
6
7
private void button1_Click(object sender, EventArgs e)
{
var bc = new BaseClass();

bc = null;
//GC.Collect(); 気長に待つことができない人は、GC.Collect()をコールしてください。
}

 しばらくすると ( GC.Collect をコールした場合は、すぐ表示されます。 )、下図のメッセージボックスが表示されます。ガーベージコレクトされました。

f:id:koogucc11:20141007022519p:plain

 上図の通り、ガーベージコレクトは行われていますが、高頻度で大量のオブジェクトを使用するようなアプリケーションの場合、ガーベージコレクトが間に合わない場合があります。下記のように、Dispose() メソッドを呼び出して、早期のオブジェクトの解放を促すのがベストです。( 下記のソースの場合、Assert のメッセージボックスは表示されません。 )

1
2
3
4
5
6
7
8
private void button1_Click(object sender, EventArgs e)
{
var bc = new BaseClass();

bc.Dispose
bc = null;
    //GC.Collect(); 気長に待つことができない人は、GC.Collect()をコールしてください。
}

 細かいことですが ( 細かくない... )、高品質なアプリケーションを開発する上で非常に重要ですね。( IDisposable インターフェイス (System) を実装しているクラスを使い終わったら、Dispose を呼ぶこと!です。 ) ※うう、もう三時だ。明日起きることができるのか.......乱文乱筆ご容赦ください。

※独習シリーズ!

独習C# 第3版

独習C# 第3版

 

※これも読んだなぁ。

[完全版] 究極のC#プログラミング ~新スタイルによる実践的コーディング

[完全版] 究極のC#プログラミング ~新スタイルによる実践的コーディング

 

※おお、もう第7版。

プログラミングC# 第7版

プログラミングC# 第7版

 
Effective C# 4.0

Effective C# 4.0

 
C#クックブック 第3版

C#クックブック 第3版