##質問
以下のようなクラスが存在する場合、このクラスにはIDisposableインターフェイスを実装するべきですか?
皆さんの意見をお聞かせください。
C#
1class Sample 2{ 3 StreamWriter _st; 4 5 public Sample() 6 { 7 // _stの初期化処理 8 ... 9 } 10}
##背景
MSDNのあるドキュメントには、直接的にアンマネージリソースを扱わない場合はIDisposableインターフェイスを実装するべきではないという記事がある一方、MSDNが提示するDisposeパターンにはマネージリソースの開放を行う場所があります。
他にも、マネージリソースのみを扱うクラスならDisposeパターンもデストラクタも使わずにDisposeメソッドを実装するだけでよいとする記事を書いている人もいます。(MSDNではないです)
IDisposableに関する様々な議論も見てはみたのですが、いまいちまとまったものがなかったので、自分で質問しながら考えを深めていこうと思いました。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
マネージリソースはとあるインスタンスとそれが内包するデータが完全にGCの対象になっているリソースで、それよりも外にある何らかのデータは全てアンマネージリソースだと思います。
ファイルやネットワーク、ビットマップ、ウィンドウなどはOSにある機能なのでこれらを示すオブジェクトはすべてアンマネージリソースで、これらをラップするクラスはIDisposableの実装が必要です(File,Socket,Image,Control等々)
また、StreamWriterのように直接アンマネージリソースを保持しませんがStreamを内包しており、これを破棄するためにIDisposableを実装するものもあります。
ですので、アンマネージリソースを直接保持する、またはIDisposableを実装するオブジェクトを保持するクラスはIDisposableを実装すべきで、Sampleクラスのような場合も必要だと思います。
あと、マネージリソースのみでも大量にメモリを使用する場合など使用者側に明示的な破棄のタイミングを提供したほうがいい場合IDisposableを実装したほうがいいと思います(MemoryStreamなど)
投稿2016/09/20 06:10
総合スコア2850
0
ベストアンサー
こんにちは。
自分なら、このクラスにはIDisposableを実装します。
フィールドにIDisposableインターフェースを持つインスタンスを設置する場合は必ずIDisposableを実装し、実装するDisposeメソッド内で全てのIDisposableなメンバー変数のDisposeメソッドを呼ぶように設計します。
Disposeパターンについては、クラス内に直接アンマネージリソースを設置する場合以外は実装する必要はないと思います。Disposeパターンは、万が一ユーザーがリソースの解放記述を行わなかった場合でもリークを回避するためのパターンです。
質問のコードの場合は、マネージリソースであるStreamWriterのみを持っているため、通常のIDisposableの実装で十分です。逆に、何も実装しないのは非常にまずいです。ユーザーがIDisposableであるStreamWriterをDisposeする手段がなくなるからです。
投稿2016/09/20 05:29
総合スコア4103
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/20 23:31
2016/09/21 00:55
2016/09/21 01:52
2016/09/21 04:06 編集
2016/09/21 04:55 編集
2016/09/21 10:41
2016/09/21 12:36
2016/09/22 10:51
0
MSDN ライブラリの以下の記事によると、"マネージリソースのみを使用する型は、ガベージコレクターによって自動的にクリアされるため、このような型で Dispose メソッドを実装しても、パフォーマンス上の利点はありません" とのことです。(current version の記事にはその説明はありませんが同じことかと思います)
Dispose メソッドの実装
https://msdn.microsoft.com/ja-jp/library/fs2xkftw(v=vs.100).aspx
しかし、実は、Dispose メソッドには、メモリ開放の機能以外に、GC.SuppressFinalize メソッド を実装することにより、冗長なファイナライザーの呼び出しを防ぐことができるという利点があるそうです。
GC.SuppressFinalize メソッド
https://msdn.microsoft.com/ja-jp/library/system.gc.suppressfinalize(v=vs.100).aspx
以下の記事の説明にも、"Dispose メソッドは、破棄するオブジェクトの SuppressFinalize メソッドを呼び出す必要があります。 SuppressFinalize を呼び出すと、オブジェクトが終了キューに置かれている場合は、そのオブジェクトの Finalize メソッドの呼び出しは行われません。Finalize メソッドの実行は、パフォーマンスに影響を与えることを覚えておいてください" と書かれています。
Dispose メソッドの実装
https://msdn.microsoft.com/ja-jp/library/fs2xkftw(v=vs.100).aspx
なので、上の記事のサンプルコードにあるように Dispose メソッドで GC.SuppressFinalize(this); を実行するようにすれば、冗長なファイナライザーの呼び出しを防ぐことができるということで、クラスに Dispose メソッドを実装することは意味がありそうです。
ただし、コンストラクタに GC.SuppressFinalize メソッドを実装できますので、冗長なファイナライザーの呼び出しを防ぐという意味では Dispose() メソッドを実装する必要はないケースもあります。
.NET のライブラリにもコンストラクタに GC.SuppressFinalize メソッドを実装しているものがあります。(例:SqlCommand クラス)
【追伸】
ひょっとして、質問者さんが書かれたサンプルコードで StreamWriter をどう Dispose するかという議論をしているのですかね?
そうあれば、ユーザーが Sample クラスの Dispose を呼ばなくても済むように、Sample クラス内で StreamWriter を使い終わったら自動的に Dispose されるようコーディングすべきだと思います。
投稿2016/09/20 05:27
編集2016/09/20 05:54退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/20 10:39
退会済みユーザー
2016/09/20 14:05
0
掲載のコードの StreamWriter _st の寿命をSampleクラスと同じにしたい場合には IDisposable を実装するのが吉です。
マネージリソースのみを扱うクラスなら Disposeパターン もデストラクタも使わずに Disposeメソッド を実装するだけでよい
その通りでしょうけど、Disposeパターンの実装はIDEがサポートしてくれますから、実際に書くコードはDisposeパターンのほうが少ないです。
投稿2016/09/20 09:12
編集2016/09/20 09:17総合スコア4150
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/09/20 14:31
2016/09/21 01:57
2016/09/21 12:47
0
使い方によると思いますが
Sample内でusingを使いdisposeするので「しない」かな
投稿2016/09/20 05:42
編集2016/09/20 06:07総合スコア200
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。