もくじ
→https://qiita.com/tera1707/items/4fda73d86eded283ec4f
Dispose関連
やりたいこと
Disposeできるクラスを書くためにIDisposableのインターフェースを実装しようと思い、IDisposableでAlt+Enterを押し、「Disposeパターンを使ってインターフェースを実装します」を選択して、出てきたコードの中に「上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。」という文言が、自分が「デストラクタ」だと思っているもの(~MyClass()のところ)に書かれているのを発見。
デストラクタ?ファイナライザ?これって何が違うのか?
あとDispose()の中でDispose(bool)を読んだりしているが、なんでそんなもの分けて作ってるのか?
ファイナライザ?の中で呼んでいるDispose(false)は何なのか?となったので、それぞれどういうものなのかはっきりしたい。
しらべたこと
はっきり言って、100%は理解できてない。主に
- 「デストラクタ」と「ファイナライザ」の違いはなにか?
- C#でDisupose()をちゃんと実装するには?
ということを調べたので、現状の理解をまとめておく。
中途半端な内容で恐縮ですが、間違いなどあれば、ご指摘頂ければ幸いです。
用語としてのファイナライザー
**多くの場合、**下記のようなものを指す。
- GCに回収された時点で呼ばれるメソッド。
- 自分で呼ばれるタイミングを制御できない。
用語としてのデストラクタ
**多くの場合、**下記のようなものを指す。
- newしたものをdeleteしたときに呼ばれるメソッド。(スコープから外れたときも)
- そのため、自分で呼ばれるタイミングを制御できる。
C#のファイナライザー
- C#にはファイナライザーを書く書き方(文法)「は存在しない。なので存在する(書ける)のはデストラクタのみ。
- C#では、MyClassクラスであれば「~MyClass()」と書いてデストラクタとなる。これが、GCに回収されるときに呼ばれるメソッドとなる。(ファイナライザ的な動作をする)
- ++C++のサイトでは、これのことを「デストラクター」と呼んでいる。こちら参照。
- C++/CLIには、デストラクタとファイナライザの両方を書く文法があるが、C#はデストラクタのみ。
- VisualStudioでIDisposableインターフェースを実装するときに「Disposeパターンを使ってインターフェースを実装します」を選択してでてくるコードのコメントの中ではこれのことを「ファイナライザ」と呼んでいるので、混乱してしまう。
- C++のデストラクタとC#のファイナライザー(の役割をするデストラクタ)の書き方が同じなので、また混乱してしまう。
- javaに、finalizeメソッドというのがあり、それが「GCに回収された時点で呼ばれる」メソッドである。C#の
ファイナライザーデストラクタはそれと同じような動きをする。
C#での実装方法
- Disposeについて
- Disposeできるクラスを作成するには、IDisposableインターフェースを実装する。
- 基本的には、Disposeは、例えばFileStreamクラスを使用して開いたファイルを使い終わったら閉じる、のように、ユーザーが自分のタイミングで使ったリソースの占有を止めるときに呼ぶものである。
- これを便利に書く書き方が、
using()
である。(usingが終わったら、書かなくてもDisposeしてくれる)
- IDisposableの実装について
-
自分でDisposeできるクラスを実装するときに、ALT+ENTを押して「Disposeパターンを使ってインターフェースを実装します」を選ぶと、Disposeパターンを自動で書いてくれる。
-
その中のDispose(bool)について、
- Dispose(true)が、Disposeで呼ばれるメソッドになる。(なる、というか、そのようにする)
- Dispose(false)が、デストラクタ(やってることとしてはファイナライザ)で呼ばれるものになる。(する)
- こちらが詳しい。
-
やっている内容としては、マネージ/アンマネージのリソースの後処理。下記の通り。
-
- マネージ/アンマネージの解放について
- デストラクタ(~MyClass()と書くやつ)には、
- マネージリソースの解放処理を書かない。
- アンマネージリソースの解放処理を書く。
- ※デストラクタでDispose(false)を呼んだ時に、これをするように作る。
- Disposeの実装には、
- マネージリソースの解放処理を書く。
- アンマネージリソースの解放処理も書く。
- ※Dispose(引数なし)でDispose(true)を呼んだ時に、これをするように作る。
- デストラクタ(~MyClass()と書くやつ)には、
- アンマネージのリソースをデストラクタにも書くのは、(もしDisposeでの開放が行われなかった場合でも)確実に開放を行うため。
- アンマネージドのリソースが無い場合は、デストラクタを書かなくてもよい。(Disposeパターンで出てくるひな形の通り、コメントアウトでOK)
備考
知りたいことは、下の「参考」のところに書かせて頂いたページにすべて書いてあるのだが、自分の現状の理解をまとめたかった次第。
参考
MsDocs デストラクタについて
https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/destructors
MsDoscs ファイナライザーについて
https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/destructors
→「ファイナライザー」の別名が「デストラクタ」だと言ってる。
デストラクター(++C++)
https://ufcpp.net/study/csharp/resource/rm_destructor/
IDisposable インターフェイスの実装
https://ufcpp.net/study/csharp/rm_disposable.html?sec=idisposable#idisposable
>「IDisposable インターフェイスの実装」の項目。
C# のファイナライザ、Dispose() メソッド、IDisposable インターフェースについて
https://qiita.com/Zuishin/items/9efc9c8cbb98300bbc64
デストラクタ
Wikipedia。ここでファイナライザについても言及されている。
https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF
>「ファイナライザ」の項を参照。短い文章だが、なんかしっくりきた。