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

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

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

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

リフレクション

リフレクションとは、プログラムの実行過程でプログラム自身の構造を読み取り、編集する事が出来るプロセスのことを指します

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

3回答

1050閲覧

C#でリフレクションを使って強制的にFinalizeを呼び出してオブジェクトを削除するとどうなるか

Takym

総合スコア22

C#

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

リフレクション

リフレクションとは、プログラムの実行過程でプログラム自身の構造を読み取り、編集する事が出来るプロセスのことを指します

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2017/10/12 01:58

編集2017/10/13 23:06

興味本位で質問します。
題名通り、以下の様にリフレクションを使って強制的にFinalizeを呼び出したらどうなるでしょうか?

C#

1var mi = obj.GetType().GetMethod( 2 "Finalize", 3 BindingFlags.NonPublic | 4 BindingFlags.InvokeMethod | 5 BindingFlags.Instance); 6mi.Invoke(obj, null); 7GC.SuppressFinalize(obj);

例えば以下の様なプログラムを実行してもエラーが発生しませんでした。

C#

1using System; 2using System.Reflection; 3 4namespace Test 5{ 6 /// <summary> 7 /// このアプリケーションのメインクラスです。 8 /// </summary> 9 public static class Program 10 { 11 /// <summary> 12 /// このアプリケーションのエントリポイントです。 13 /// </summary> 14 /// <param name="args">コマンドライン引数を取得します。</param> 15 /// <returns>OSに実行結果を表す数値を返します。</returns> 16 [STAThread()] 17 public static int Main(params string[] args) 18 { 19 // 普通のオブジェクトを削除する 20 object a = new object(); 21 Console.WriteLine("Delete前(a):" + a); 22 Delete(a); 23 GC.Collect(); // これを呼び出してメモリから完全に削除する 24 Console.WriteLine("Delete後(a):" + a); 25 26 // 簡易的なオブジェクトを削除する 27 Data b = new Data("Hello, World!!"); 28 Console.WriteLine("Delete前(b.Text):" + b.Text); 29 Delete(b); 30 GC.Collect(); // これを呼び出してメモリから完全に削除する 31 Console.WriteLine("Delete後(b.Text):" + b.Text); 32 33 // バイト配列を削除する 34 byte[] c = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 35 Console.WriteLine("Delete前(c):" + string.Join(",", c)); 36 Delete(c); 37 GC.Collect(); // これを呼び出してメモリから完全に削除する 38 Console.WriteLine("Delete後(c):" + string.Join(",", c)); 39 40 // バイト配列を保持したオブジェクトを削除する 41 Data2 d = new Data2(9, 8, 7, 6, 5, 4, 3, 2, 1, 0); 42 Console.WriteLine("Delete前(d.Values):" + string.Join(",", d.Values)); 43 Delete(d); 44 GC.Collect(); // これを呼び出してメモリから完全に削除する 45 Console.WriteLine("Delete後(d.Values):" + string.Join(",", d.Values)); 46 47 Console.ReadKey(true); 48 49 return 0; 50 } 51 52 /// <summary> 53 /// 指定したオブジェクトのデストラクタを呼び出して削除します。 54 /// </summary> 55 /// <param name="obj">削除するオブジェクトです。</param> 56 public static void Delete(object obj) 57 { 58 var mi = obj.GetType().GetMethod( 59 "Finalize", 60 BindingFlags.NonPublic | 61 BindingFlags.InvokeMethod | 62 BindingFlags.Instance); 63 mi.Invoke(obj, null); 64 GC.SuppressFinalize(obj); 65 } 66 67 /// <summary> 68 /// 文字列データを保持するクラスです。 69 /// </summary> 70 public class Data 71 { 72 /// <summary> 73 /// 文字列データです。 74 /// </summary> 75 public string Text { get; set; } 76 77 /// <summary> 78 /// 型'<see cref="Test.Program.Data"/>'の新しいインスタンスを生成します。 79 /// </summary> 80 /// <param name="str">このクラスに保存する文字列です。</param> 81 public Data(string str) { 82 this.Text = str; 83 } 84 85 /// <summary> 86 /// 現在のオブジェクトのリソースを解放します。 87 /// </summary> 88 ~Data() { 89 this.Text = null; 90 Console.WriteLine("デストラクタが呼び出されました。"); 91 } 92 } 93 94 /// <summary> 95 /// バイト配列を保持するクラスです。 96 /// </summary> 97 public class Data2 98 { 99 /// <summary> 100 /// バイト配列です。 101 /// </summary> 102 public byte[] Values { get; set; } 103 104 /// <summary> 105 /// 型'<see cref="Test.Program.Data2"/>'の新しいインスタンスを生成します。 106 /// </summary> 107 /// <param name="values">このクラスに保存するバイト配列です。</param> 108 public Data2(params byte[] values) { 109 this.Values = values; 110 } 111 } 112 } 113}

コンソールには以下の様に表示されました。

Delete前(a):System.Object Delete後(a):System.Object Delete前(b.Text):Hello, World!! デストラクタが呼び出されました。 Delete後(b.Text): Delete前(c):0,1,2,3,4,5,6,7,8,9 Delete後(c):0,1,2,3,4,5,6,7,8,9 Delete前(d.Values):9,8,7,6,5,4,3,2,1,0 Delete後(d.Values):9,8,7,6,5,4,3,2,1,0

強制的にFinalizeを呼び出す事により何か問題が発生するのでしょうか?それとも発生しないのでしょうか?
ご回答お待ちしています。
######環境
OS: Microsoft Windows 10 Creators Update
ランタイム: .NET Framework v4.7
######補足
ここで得られた回答の一部を自分のブログに投稿してもよろしいでしょうか?
引用元は必ず明記します。

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

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

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

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

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

guest

回答3

0

ベストアンサー

間違っているならご指摘お願いします。

これはリフレクションを使用するしないの違いはないのではないかと思います。

C#

1// 普通のオブジェクトを削除する 2object a = new object(); 3Console.WriteLine("Delete前(a):" + a); 4Delete(a); 5GC.Collect(); // 1 6Console.WriteLine("Delete後(a):" + a); // 2 7a = null;  // 3 8GC.Collect(); // 4

1の段階ではaのインスタンスは参照されているのでGC対象にならず存在している。
なので、2でアクセスできている。
3でインスタンスの参照がなくなるのでGC対象となり、4でメモリから消える

DataクラスのようにFinalize時に自分の使用している資源を解放するようなクラスの場合は
Finalize後にアクセスすることによりエラーが発生する可能性があると思います。
(サンプルでは文字列の削除のみなので問題は出ていませんが)

その他の場合、インスタンスの参照がなくなるまではエラーが出ないとは思いますが
Finalize後にそのインスタンスを使用するのはやってはいけないですよね。

要はリフレクションによるFinalizeの呼び出しが問題なのではなく、Finalize後にそのインスタンスを利用するのが問題かと思います。

投稿2017/10/12 02:44

YAmaGNZ

総合スコア10242

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

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

Takym

2017/10/13 01:42

そうですね。Deleteメソッドを実行した後に、削除したオブジェクトにアクセスする事自体間違っていますね。
guest

0

他の方の言う通り単なるメソッド(イベント)なので、実行して問題が起こることはないと思います。デストラクタ実行前に暗黙で呼ばれるというだけです。

最後にやるべき処理をFinalizeに書く半面、それ以外のタイミングにやったらまずいことを書く印象があります。リソースの開放などがそれにあたる処理です。

「(マナーとして)やるべきではない」という点を他の方の意見に追加したいと思います。

投稿2017/10/12 03:09

iwamoto_takaaki

総合スコア2883

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

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

Takym

2017/10/13 01:45

>「(マナーとして)やるべきではない」 言われてから気づきました。 確かに、リフレクションは普段は実行しませんよね。
guest

0

まず最初にお断りとして、きちんと検証したうえでの回答ではありません。

リフレクションを使って強制的にFinalizeを呼び出したらどうなるでしょうか?

Finalizeはオブジェクトの削除時に呼ばれるメソッドではありますが、Finalizeが呼ばれたらからといってオブジェクトが削除されるわけではないかと思います。

C#

1// 普通のオブジェクトを削除する 2object a = new object(); 3Console.WriteLine("Delete前(a):" + a); 4Delete(a); 5GC.Collect(); // これを呼び出してメモリから完全に削除する 6Console.WriteLine("Delete後(a):" + a);

上記でGC.Collect();を実行していますが、このタイミングではaはまだオブジェクトを参照しているため、該当のオブジェクトはGCの対象とはならないものと思われます。
そのため、GC実行後もaは問題なく参照が可能となっている認識です。

投稿2017/10/12 02:37

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Takym

2017/10/13 01:41

言われてみればそうですね。Finalizeはメソッドであって、GCによりオブジェクトが破棄される時に呼び出されるだけですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問