Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8899

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

$
0
0

もくじ
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
>「ファイナライザ」の項を参照。短い文章だが、なんかしっくりきた。


Viewing all articles
Browse latest Browse all 8899

Trending Articles