前提・実現したいこと
アンマネージリソースを含むクラスの破棄周りについて学習しています。
Dispose()を呼び忘れたまま参照を新しいインスタンスで上書きした場合でも、
それまで参照されていたインスタンスのファイナライザが即時呼ばれ、アンマネージリソースが
無事に解放されるようにしたいと思っています。
そこで、C#で、C++のshared_ptrやunique_ptrのように、インスタンスの参照カウントが0になった
タイミングで即座に破棄コードが呼ばれるような仕組みを作ることは可能でしょうか?
下記コードのような動作を所望しております。
サンプルコード
C#
1MyClass m = new MyClass(); 2...(中略) 3m = new MyClass(); // <-ここで前回newしたインスタンスが破棄される
試したこと
解放タイミングを確認するためにGC.Collect()を呼び出して様子を見たりはしましたが、
そもそもガベージコレクションの意識すらさせない仕組みができれば、と思っております。
ただ、WEB上のドキュメントを拝見している限りでは
- 基本的にはDispose()をちゃんと呼ぶこと
- Dispose()を呼び忘れても、GC時に呼ばれるファイナライザで破棄できるようDisposeパターンを実装しておくこと
が原則のように思われ、今回のような使い方は考えない方がよいのかなと思案しているところです。
すみませんが、指南いただけますと助かります。
環境
現在使用している環境は下記のとおりです。
.Net Framework 4.5
C# 7.3
Dispose パターンに従って Dispose メソッドを実装し、using 句を使うようにすれば質問に書いてあるようなことは考えずに済むはずですが、そのあたりは十分ご承知の上で質問に書いてある仕組みを実装したいということですか? 仕組みを作ることの労力・工数に見合うメリットが分からないのですが、どういうことを考えておられるのか教えていただけませんか?
言葉が足らずすみません。
まずusing句についてですが、アンマネージリソースを含むクラスのインスタンスの参照を別のクラスのメンバとして持つことを想定しています。こういったシチュエーションではusingが使えないという認識でおります。
メリットについてですが、前述のようにusing句が使えない状況ですので、Dispose()を意識しなくてもC++のスマートポインタ並みに破棄のタイミングが明確になること自体が大きなメリットと捉えております。
もし、認識に誤りがありましたらご指摘いただけますと幸甚です。
> こういったシチュエーションではusingが使えないという認識でおります。
そんなことはないはずです。そこが誤解で、そもそも必要のないことを考えておられるような気がするのですが? その具体例を書いてください。
一点追記です。
実は、アンマネージリソースを含むクラスを、ゆくゆくは共同開発者に使ってもらう予定があります。ただ彼らは初心者のため、たとえ不注意をしでかしたとしてもリソースリークが起きないような仕組みがあればいいなというのが事の発端です。ですので、動機が不純であることは重々承知しております...
そういうのは、例えば、SqlConnection を Open しても Close しないような初心者に対応する自動的仕組みを作りたいと言うのと同じようなことで、無理だと思うのですが?
真っ当な方法では不可能ですし、仮に無理やり実現したとしても他のクラス設計に影響が及んだり別の弊害が出たりすると思います。
やめた方が無難です。
SurferOnWwwさん、NotionalKettleさん
コメント大変ありがとうございます。
もし世の中に一般的に使われているイディオムのようなものがあれば、と思い投稿致しましたが、やはりやめておいた方がよいということを理解できました。
すみません、一点、SurferOnWww様からのコメントにあった件で。
>> こういったシチュエーションではusingが使えないという認識でおります。
>そんなことはないはずです。そこが誤解で、そもそも必要のないことを考えておられるような気がするのですが? その具体例を書いてください。
いま私が存じ上げているusingの使い方というのが、メソッド内で
using(MyClass mc = new MyClass()) {...}
とするような使い方です。
しかしここで、例えばMyClassのインスタンスへの参照を他のクラスがメンバとして持ち、複数のメソッドで使いまわすような場合に、using句によってインスタンス破棄を行う方法を残念ながら思いつきませんでした。ほかにもusingを用いることができるシチュエーションがあるということでしょうか。
そもそも、アンマネージリソースを含むインスタンスをクラスメンバとして保持し続けること自体がイレギュラー、やらない方がいい、ということでしょうか。
C#では、IDisposable なインスタンスは、明示的なDispose()をするプログラミングパターンになっています。finalizer を使用して、GC に委ねるパラターンもありますが、バグやメモリーリークの原因になるので、Dispose()をコールするか、using を使うのが普通です。静的な、コードアナライザーを有効にする事で、見落としがないように防ぐことができます。
> 例えばMyClassのインスタンスへの参照を他のクラスがメンバとして持ち・・・usingを用いることができるシチュエーションがあるということでしょうか。
もちろんです。
MyClass を IDisposable インターフェイスを継承して Dispose パターンに従って Dispose メソッド等を実装すれば using の {...} を抜けるところで Dispose されます。たとえ {...} の中で例外が発生しても Dispose されます。
> アンマネージリソースを含むインスタンスをクラスメンバとして保持し続けること自体がイレギュラー・・・
そんなことはないです。
そもそも、アンマネージドリソースを開放する目的で Dispose パターンを実装するのです。マネージドリソースのみなら全て GC に任せておけばよく、Dispose を実装する必要はありません。
Dispose パターン
http://surferonwww.info/BlogEngine/post/2019/05/31/dispose-pattern.aspx
ご返信ありがとうございます。
すみません、私のusing句の理解につきまして、またしても言葉足らずでした。具体的には、下記のような状況を想定していました。
class OwnerClass
{
private MyClass mc;
public OwnerClass() { mc = new MyClass(); }
public method1() { // mcを使った処理1 };
public method2() { // mcを使った処理2 };
...
}
このように、一度獲得したMyClassインスタンスを複数のメソッドで使いまわしたい場合、MyClassインスタンスの寿命をusing句によってコントロールすることはできないのでは、ということが申し上げたかった次第です。
OwnerClassにIDisposableを実装したら良いだけでは?
先に紹介した記事 ↓ 読みました?
Dispose パターン
http://surferonwww.info/BlogEngine/post/2019/05/31/dispose-pattern.aspx
その中の「上記 1 のケース」で、DataSet が質問者さんの MyClass と思ってください。それで分かりませんか? せっかく紹介したのですからよく読んでから聞きましょうよ。
Dispose パターンの実装方法の話になるのであれば、このスレッドはクローズして、新たに別のスレッドを立てて質問してください。
>hihijiji様
ありがとうございます。やはりOwnerClass側でIDisposableを実装するのが本道なのですね。
元々の考え(希望)は、こうでした。
・OwnerClass側は、メンバとして抱えているMyClassクラスがアンマネージリソースを含むかどうか意識したくない。
・つまり、OwnerClassはMyClassの破棄(Dispose)を明示的に行わなくてもいいようにしたい。
・なので、OwnerClassが破棄されMyClassインスタンスへの参照が無くなったタイミングで、MyClassも勝手に、即座に破棄されて欲しい。
C++のスマートポインタではそのような設計ができるので、似たようなことができないかな?というのが元の考えでした。
>SurferOnWww様
もちろん、記事は拝見した上でおうかがいしました。
ただ、本コメントの前半で申し上げた通り、当該記事でいうところのサンプルクラスDisposableSample側では、出来る限り子リソースの破棄について意識したくない、というのが疑問の骨子としてあったため、解決には至らなかったのでした。うまくお伝えできずすみません。
ご返信くださった皆様、ありがとうございました。
当初目論んでいたかたちでの設計はできないということで納得できました。
本件はクローズさせていただきます。
前にも言いましたけど、そういうことは、100% 不可能・・・とまでは言いませんが無理です。少なくとも全く現実的ではありません。もういい加減にしましょう。私は撤退します。
>SurferOnWww様
素敵な捨て台詞をありがとうございます。
ではこちらも、(C#使いの方から見て)頓珍漢な質問をしたことを棚に上げてコメントさせていただきますが、いい加減にしてほしいのはこちらでした。他の方は私のやりたいことを汲み取ったうえでコメントしていただいており、大変有難かったですが、貴方は質問意図を理解する気がさらさら無かったのではないかと思います。ネイティブコードの経験者がC#を扱ううえで抱きそうな疑問について、想像もつきませんでしたか?
初質問ということもあり、コメントをいただけるだけで有難いという謙虚な気持ちで居ようと努力しましたが、素敵な捨て台詞をいただきましたので、以上、一言いわせていただきました。
他のご返信くださった方々には不快な思いをさせてしまい申し訳ございません。ダイレクトメッセージのようなものがあればそちらを使いたかったですが…
あなたはブラックリストに入れときますので、ハンドル名は変えないよう。
ありがとうございます!
BL 入りおめでとう!
回答1件
あなたの回答
tips
プレビュー