質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

3456閲覧

C# Dispose()を呼ばずに参照カウント0のインスタンスを即時破棄したい

reg_ama_gir

総合スコア16

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

0クリップ

投稿2020/01/21 02:35

前提・実現したいこと

アンマネージリソースを含むクラスの破棄周りについて学習しています。

Dispose()を呼び忘れたまま参照を新しいインスタンスで上書きした場合でも、
それまで参照されていたインスタンスのファイナライザが即時呼ばれ、アンマネージリソースが
無事に解放されるようにしたいと思っています。

そこで、C#で、C++のshared_ptrやunique_ptrのように、インスタンスの参照カウントが0になった
タイミングで即座に破棄コードが呼ばれるような仕組みを作ることは可能でしょうか?

下記コードのような動作を所望しております。

サンプルコード

C#

1MyClass m = new MyClass(); 2...(中略) 3m = new MyClass(); // <-ここで前回newしたインスタンスが破棄される

試したこと

解放タイミングを確認するためにGC.Collect()を呼び出して様子を見たりはしましたが、
そもそもガベージコレクションの意識すらさせない仕組みができれば、と思っております。

ただ、WEB上のドキュメントを拝見している限りでは

  1. 基本的にはDispose()をちゃんと呼ぶこと
  2. Dispose()を呼び忘れても、GC時に呼ばれるファイナライザで破棄できるようDisposeパターンを実装しておくこと

が原則のように思われ、今回のような使い方は考えない方がよいのかなと思案しているところです。

すみませんが、指南いただけますと助かります。

環境

現在使用している環境は下記のとおりです。
.Net Framework 4.5
C# 7.3

fana👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/01/21 02:59

Dispose パターンに従って Dispose メソッドを実装し、using 句を使うようにすれば質問に書いてあるようなことは考えずに済むはずですが、そのあたりは十分ご承知の上で質問に書いてある仕組みを実装したいということですか? 仕組みを作ることの労力・工数に見合うメリットが分からないのですが、どういうことを考えておられるのか教えていただけませんか?
reg_ama_gir

2020/01/21 03:13 編集

言葉が足らずすみません。 まずusing句についてですが、アンマネージリソースを含むクラスのインスタンスの参照を別のクラスのメンバとして持つことを想定しています。こういったシチュエーションではusingが使えないという認識でおります。 メリットについてですが、前述のようにusing句が使えない状況ですので、Dispose()を意識しなくてもC++のスマートポインタ並みに破棄のタイミングが明確になること自体が大きなメリットと捉えております。 もし、認識に誤りがありましたらご指摘いただけますと幸甚です。
退会済みユーザー

退会済みユーザー

2020/01/21 03:14 編集

> こういったシチュエーションではusingが使えないという認識でおります。 そんなことはないはずです。そこが誤解で、そもそも必要のないことを考えておられるような気がするのですが? その具体例を書いてください。
reg_ama_gir

2020/01/21 03:15

一点追記です。 実は、アンマネージリソースを含むクラスを、ゆくゆくは共同開発者に使ってもらう予定があります。ただ彼らは初心者のため、たとえ不注意をしでかしたとしてもリソースリークが起きないような仕組みがあればいいなというのが事の発端です。ですので、動機が不純であることは重々承知しております...
退会済みユーザー

退会済みユーザー

2020/01/21 03:20

そういうのは、例えば、SqlConnection を Open しても Close しないような初心者に対応する自動的仕組みを作りたいと言うのと同じようなことで、無理だと思うのですが?
退会済みユーザー

退会済みユーザー

2020/01/21 03:37

真っ当な方法では不可能ですし、仮に無理やり実現したとしても他のクラス設計に影響が及んだり別の弊害が出たりすると思います。 やめた方が無難です。
reg_ama_gir

2020/01/21 04:17

SurferOnWwwさん、NotionalKettleさん コメント大変ありがとうございます。 もし世の中に一般的に使われているイディオムのようなものがあれば、と思い投稿致しましたが、やはりやめておいた方がよいということを理解できました。 すみません、一点、SurferOnWww様からのコメントにあった件で。 >> こういったシチュエーションではusingが使えないという認識でおります。 >そんなことはないはずです。そこが誤解で、そもそも必要のないことを考えておられるような気がするのですが? その具体例を書いてください。 いま私が存じ上げているusingの使い方というのが、メソッド内で using(MyClass mc = new MyClass()) {...} とするような使い方です。 しかしここで、例えばMyClassのインスタンスへの参照を他のクラスがメンバとして持ち、複数のメソッドで使いまわすような場合に、using句によってインスタンス破棄を行う方法を残念ながら思いつきませんでした。ほかにもusingを用いることができるシチュエーションがあるということでしょうか。 そもそも、アンマネージリソースを含むインスタンスをクラスメンバとして保持し続けること自体がイレギュラー、やらない方がいい、ということでしょうか。
mmaeda

2020/01/21 04:35

C#では、IDisposable なインスタンスは、明示的なDispose()をするプログラミングパターンになっています。finalizer を使用して、GC に委ねるパラターンもありますが、バグやメモリーリークの原因になるので、Dispose()をコールするか、using を使うのが普通です。静的な、コードアナライザーを有効にする事で、見落としがないように防ぐことができます。
退会済みユーザー

退会済みユーザー

2020/01/21 04:44 編集

> 例えばMyClassのインスタンスへの参照を他のクラスがメンバとして持ち・・・usingを用いることができるシチュエーションがあるということでしょうか。 もちろんです。 MyClass を IDisposable インターフェイスを継承して Dispose パターンに従って Dispose メソッド等を実装すれば using の {...} を抜けるところで Dispose されます。たとえ {...} の中で例外が発生しても Dispose されます。 > アンマネージリソースを含むインスタンスをクラスメンバとして保持し続けること自体がイレギュラー・・・ そんなことはないです。 そもそも、アンマネージドリソースを開放する目的で Dispose パターンを実装するのです。マネージドリソースのみなら全て GC に任せておけばよく、Dispose を実装する必要はありません。 Dispose パターン http://surferonwww.info/BlogEngine/post/2019/05/31/dispose-pattern.aspx
reg_ama_gir

2020/01/21 06:01

ご返信ありがとうございます。 すみません、私のusing句の理解につきまして、またしても言葉足らずでした。具体的には、下記のような状況を想定していました。 class OwnerClass { private MyClass mc; public OwnerClass() { mc = new MyClass(); } public method1() { // mcを使った処理1 }; public method2() { // mcを使った処理2 }; ... } このように、一度獲得したMyClassインスタンスを複数のメソッドで使いまわしたい場合、MyClassインスタンスの寿命をusing句によってコントロールすることはできないのでは、ということが申し上げたかった次第です。
hihijiji

2020/01/21 06:14

OwnerClassにIDisposableを実装したら良いだけでは?
退会済みユーザー

退会済みユーザー

2020/01/21 06:32

先に紹介した記事 ↓ 読みました? Dispose パターン http://surferonwww.info/BlogEngine/post/2019/05/31/dispose-pattern.aspx その中の「上記 1 のケース」で、DataSet が質問者さんの MyClass と思ってください。それで分かりませんか? せっかく紹介したのですからよく読んでから聞きましょうよ。
退会済みユーザー

退会済みユーザー

2020/01/21 06:42

Dispose パターンの実装方法の話になるのであれば、このスレッドはクローズして、新たに別のスレッドを立てて質問してください。
reg_ama_gir

2020/01/21 06:43

>hihijiji様 ありがとうございます。やはりOwnerClass側でIDisposableを実装するのが本道なのですね。 元々の考え(希望)は、こうでした。 ・OwnerClass側は、メンバとして抱えているMyClassクラスがアンマネージリソースを含むかどうか意識したくない。 ・つまり、OwnerClassはMyClassの破棄(Dispose)を明示的に行わなくてもいいようにしたい。 ・なので、OwnerClassが破棄されMyClassインスタンスへの参照が無くなったタイミングで、MyClassも勝手に、即座に破棄されて欲しい。 C++のスマートポインタではそのような設計ができるので、似たようなことができないかな?というのが元の考えでした。 >SurferOnWww様 もちろん、記事は拝見した上でおうかがいしました。 ただ、本コメントの前半で申し上げた通り、当該記事でいうところのサンプルクラスDisposableSample側では、出来る限り子リソースの破棄について意識したくない、というのが疑問の骨子としてあったため、解決には至らなかったのでした。うまくお伝えできずすみません。
reg_ama_gir

2020/01/21 06:49

ご返信くださった皆様、ありがとうございました。 当初目論んでいたかたちでの設計はできないということで納得できました。 本件はクローズさせていただきます。
退会済みユーザー

退会済みユーザー

2020/01/21 06:51

前にも言いましたけど、そういうことは、100% 不可能・・・とまでは言いませんが無理です。少なくとも全く現実的ではありません。もういい加減にしましょう。私は撤退します。
reg_ama_gir

2020/01/21 07:09

>SurferOnWww様 素敵な捨て台詞をありがとうございます。 ではこちらも、(C#使いの方から見て)頓珍漢な質問をしたことを棚に上げてコメントさせていただきますが、いい加減にしてほしいのはこちらでした。他の方は私のやりたいことを汲み取ったうえでコメントしていただいており、大変有難かったですが、貴方は質問意図を理解する気がさらさら無かったのではないかと思います。ネイティブコードの経験者がC#を扱ううえで抱きそうな疑問について、想像もつきませんでしたか? 初質問ということもあり、コメントをいただけるだけで有難いという謙虚な気持ちで居ようと努力しましたが、素敵な捨て台詞をいただきましたので、以上、一言いわせていただきました。 他のご返信くださった方々には不快な思いをさせてしまい申し訳ございません。ダイレクトメッセージのようなものがあればそちらを使いたかったですが…
退会済みユーザー

退会済みユーザー

2020/01/21 08:02

あなたはブラックリストに入れときますので、ハンドル名は変えないよう。
reg_ama_gir

2020/01/21 08:05

ありがとうございます!
退会済みユーザー

退会済みユーザー

2020/01/21 14:17

BL 入りおめでとう!
guest

回答1

0

自己解決

さまざまコメントをいただき、タイトルにあるような設計は基本的に不可能、
やらない方がよいということで納得できました。
コメントくださった方々、大変ありがとうございました。

投稿2020/01/21 06:52

reg_ama_gir

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/01/21 14:22 編集

さまざまって、誰のコメントが役に立ったと言ってます?
退会済みユーザー

退会済みユーザー

2020/01/21 14:22 編集

「他の方は私のやりたいことを汲み取ったうえでコメントしていただいており」とか言ってますが、他の方のコメントのどこがどのように問題解決に役立だったのか書きましょう。それを書かないのは他の方に失礼ですよ。
fana

2020/01/22 05:39 編集

私はC++→C#の順で入ったので,この質問の疑問点はわかる気がします. class MyClass : IDisposable {...} //MyClassはDispose()呼ばないとダメ class TestClass { private MyClass m_MyClass; public TestClass( MyClass mc ){ m_MyClass=mc; } //ctorで参照が渡されてくる public DoSomething(){ m_MyClass.SomeMethod(); } } とかいう場合において, 複数個のTestClassインスタンスに同一のMyClassインスタンスへの参照が渡されている(且つ,そのMyClassインスタンスへの参照は他には残っていない)ような場合,だれがいつMyClassのDispose()を呼べばよいの??とか.(この場合の解は「そんな状態にするな」なのか?とか思っている)
reg_ama_gir

2020/01/22 05:56

>fana様 コメントありがとうございます。まさに仰る通りの疑問があります。 参照元が複数あり参照カウントがいつゼロになるかの判定が難しい状況において、インスタンスが不要になった時点で即破棄されて欲しい(=GC任せにしたくない)リソースの扱いをどうしたらいいのかと… C++のようなことはできないと割り切ったうえで設計すべきということなのだと理解しました。
YAmaGNZ

2020/01/22 06:15

fanaさんの例だと、TestClassから見たら、知らんがなってことになるんじゃないですかね? 与えられたものがどういう状況か判断できませんし、与えた側が管理すべきことかと思います。
fana

2020/01/22 06:25

> TestClassから見たら、知らんがなってことになるんじゃないですかね? はい.なので,だれか(与えた側)がどうにかして解決しなきゃならない以上, > (且つ,そのMyClassインスタンスへの参照は他には残っていない) なんて話にしちゃダメってことですよね.
Zuishin

2020/01/22 06:27

まず参照カウントというものが無いので、前提から間違えています。 次に、using ブロック内にあるものを別のタイミングで破棄したい、あるいは延命させたいというのも間違っています。 そして、意味不明で妖怪じみた「ぼくのかんがえたさいきょうのしよう」を他人に使わせようというのが一番の間違いです。普通に使えば済むことです。 Dispose の仕方は using だけではありません。ライフサイクルが他のオブジェクトに依存する場合はそのオブジェクトに IDisposable を実装すべきです。
reg_ama_gir

2020/01/22 06:39

>Zuishin様 コメントありがとうございます。 ついC++を基準に「これはできないのかな?」という目線で見てしまっていたため、C#の常識から逸脱してしまっていました。今見返すとおかしな質問だったと分かります。 >普通に使えば済むことです。 質問を書いた時点では「何が普通か」すら理解していなかったため、簡便な方法で実現することができないか?と思い質問を投稿してしまいました。私の説明が拙かったこともあり、話題をややこしくしてしまいまして申し訳ありません。ご指摘ありがとうございます。
退会済みユーザー

退会済みユーザー

2020/01/28 10:07

>この場合の解は「そんな状態にするな」なのか?とか思っている 今更ながら気になって考えたのですが、画像データとか何度もインスタンス化したくはないが分配したいというものはありますし、インスタンス生成元が責任もっておけという訳にも行かないケースも無くもなさそうです。 Proxyパターン+staticなDictionary+参照カウンタ(newで+1, Disposeで-1)で上手いこと出来るような気はします。 いずれにせよDisposeを呼ばないことにはGC任せなので質問者さんの話は解決しませんが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問