LoginSignup
7
10

More than 3 years have passed since last update.

[C#] デストラクタとDisposeについて

Last updated at Posted at 2019-11-12

もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f

Dispose関連
- 【C#】Disposeとは?
- [C#] デストラクタとDisposeについて

やりたいこと

Disposeできるクラスを書くためにIDisposableのインターフェースを実装しようと思い、IDisposableでAlt+Enterを押し、「Disposeパターンを使ってインターフェースを実装します」を選択して、出てきたコードの中に「上の Dispose(bool disposing) にアンマネージ リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします。」という文言が、自分が「デストラクタ」だと思っているもの(~MyClass()のところ)に書かれているのを発見。
image.png

デストラクタ?ファイナライザ?これって何が違うのか?
あと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パターンを自動で書いてくれる。
    • image.png
    • その中のDispose(bool)について、
      • Dispose(true)が、Disposeで呼ばれるメソッドになる。(なる、というか、そのようにする)
      • Dispose(false)が、デストラクタ(やってることとしてはファイナライザ)で呼ばれるものになる。(する)
    • こちらが詳しい。
    • やっている内容としては、マネージ/アンマネージのリソースの後処理。下記の通り。
  • マネージ/アンマネージの解放について

    • デストラクタ(~MyClass()と書くやつ)には、
      • マネージリソースの解放処理を書かない。
      • アンマネージリソースの解放処理を書く。
      • ※デストラクタでDispose(false)を呼んだ時に、これをするように作る。
    • Disposeの実装には、
      • マネージリソースの解放処理を書く。
      • アンマネージリソースの解放処理も書く。
      • ※Dispose(引数なし)でDispose(true)を呼んだ時に、これをするように作る。
  • アンマネージのリソースをデストラクタにも書くのは、(もし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
>「ファイナライザ」の項を参照。短い文章だが、なんかしっくりきた。

7
10
2

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
7
10