C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: プログラム終了時にコードを実行


(過去ログ 161 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■93449 / inTopicNo.1)  プログラム終了時にコードを実行
  
□投稿者/ ぼやっき (1回)-(2019/12/12(Thu) 13:03:06)

分類:[.NET 全般] 


Sub New()

End Sub

を使うとプログラム開始時(モジュール生成時)に実行するコードを記述することができます。

一方で、プログラム終了時に実行するコードはどのようにして記述すれば良いですか?

Form1_Closingでもできるのですが、
モジュールごとに分けて記述したいのですが
どうすれば良いですか?
引用返信 編集キー/
■93450 / inTopicNo.2)  Re[1]: プログラム終了時にコードを実行
□投稿者/ 中 (3回)-(2019/12/12(Thu) 13:10:46)
try finallyを使うのが基本だけど、なんか違う想定をしていそう。
もうすこしサンプルコード書いてみて
引用返信 編集キー/
■93456 / inTopicNo.3)  Re[1]: プログラム終了時にコードを実行
□投稿者/ 魔界の仮面弁士 (2523回)-(2019/12/12(Thu) 13:37:40)
No93449 (ぼやっき さん) に返信
> Sub New()
>
> End Sub
> を使うとプログラム開始時(モジュール生成時)に実行するコードを記述することができます。

う〜ん。Module で Sub New が必要になることって、あまり無い気がするのですけれども。

Friend Module Module1
 Public ReadOnly sample As Long
 Sub New()
  sample = Now.Ticks
 End Sub
End Module


Module ではなく、Class のインスタンス管理でも良いのなら、
ファイナライザを使うという力業がありますが…。

Public Class Class1
Public Sub New()

End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
End Class



> 一方で、プログラム終了時に実行するコードはどのようにして記述すれば良いですか?
アプリ全体の終了時で良いのなら、プロジェクトのプロパティを開いて
[アプリケーション] タブにある[アプリケーション イベントの表示]ボタンから
MyApplication の Shutdown イベントを記述します。



> モジュールごとに分けて記述したいのですが
Module は Shared に近い意味合いを持つので、最初にアクセスした時点でロードされ、
それ以降はずっと読み込まれたままになります。アプリ終了まで残り続けます。
アプリケーション ドメインを分けてアンロードするといったことはできますが、
終了通知のイベントのようなものは無かったと思います。

もしも寿命管理の意図ならば、Module ではなくシングルトンな Class インスタンスに
書き換えることを検討してみてください。必要に応じて IDisposable パターンにもできるでしょうし。
引用返信 編集キー/
■93462 / inTopicNo.4)  Re[2]: プログラム終了時にコードを実行
□投稿者/ ぼやっき (2回)-(2019/12/12(Thu) 16:04:09)
すいません、質問がわかりにくかったかも知れません。

以下のようにモジュール内のプライベート変数で
ペンを定義しています。

Public Module Module1

	dim pPen As New Pen(Color.FromArgb(255, 0, 255), 2))

 Sub New()
  ' sample = Now.Ticks
 End Sub



Sub aaa()
   
     g.DrawLine(pPen, 1, 2, 3, 4)

End Sub


End Module


このペンはプログラム終了時にDisposeする必要があると思います。

このような、ペンを定義したモジュールが複数個あります。


もし、MyApplication の Shutdown イベントやForm1_Closingで
disposeするのなら、
ペン変数をpublic変数として定義する必要があり、
モジュール間で同じ同じ名称を使うことができません。
また、たくさんモジュールがあると、ペン変数の管理が面倒であるため、
モジュールごとにdiposeしたいと考えています。



> Module は Shared に近い意味合いを持つので、最初にアクセスした時点でロードされ、
> それ以降はずっと読み込まれたままになります。アプリ終了まで残り続けます。
> アプリケーション ドメインを分けてアンロードするといったことはできますが、
> 終了通知のイベントのようなものは無かったと思います。

ということはクラスでないとできないということでしょうか?

ペン変数はシャットダウン時にdiposeしないとメモリ内に残り続けるのでしょうか?



引用返信 編集キー/
■93466 / inTopicNo.5)  Re[3]: プログラム終了時にコードを実行
□投稿者/ 中 (8回)-(2019/12/13(Fri) 00:26:26)
まぁプログラム終了時には解放されるはずですが・・・できれば解放したいところですね。
であればクラスにするのが一番だとは思います。
引用返信 編集キー/
■93469 / inTopicNo.6)  Re[3]: プログラム終了時にコードを実行
□投稿者/ 魔界の仮面弁士 (2526回)-(2019/12/13(Fri) 10:24:56)
2019/12/13(Fri) 10:41:07 編集(投稿者)

No93462 (ぼやっき さん) に返信
> ペンを定義しています。
実際にはその Pen が複数あるわけですよね。
そのコードだと、たとえまだ Pen を必要としていなかったとしても、
Module1 上の何かにアクセスした瞬間に、Pen が一斉に生成されることになります。

フィールドではなく、プロパティとして実装してみては如何でしょうか。
たとえば Pens.Blue 等のように。
https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Pens.cs,342

そうすれば、Module のロード時ではなく、それぞれの Pen インスタンスが
本当に必要になった瞬間に初めて生成されるようにできます。


また、管理対象の Pen を保持しておくコレクションを用意するのはどうでしょう。
そうすれば、後からそのコレクションを参照することで、生成済みの
Pen を列挙できるので、まとめて Dispose することも楽になるかと。

開いているフォームの一覧を Application.OpenForms で列挙したり、
フォーム上のコントロールの一覧を、Controls プロパティで得られるわけですが、
それと同じように、自己管理している Pen の一覧を保持するような
コレクションを自作しておく、ということです。


> このペンはプログラム終了時にDisposeする必要があると思います。
寿命管理にはいろいろなパターンがあろうかと思いますが、基本は、
「必要になったら生成」「使い終わったら処分する」だと思います。


オブジェクトの生成タイミングを制御できるのは、開発者自身ですが、
それと同様、使い終わったという事を明示できるのも、開発者自身のはず。

たとえばメモ帳が、ファイルを作成→保存して閉じる、という流れを持つように、
描画用の Pen を作成→もう描画しなくなったので Dispose しておく、という流れです。

もちろん、アプリ終了時は「もう使わない」ことが確実なので、
プログラム終了時に、明示的に処分命令を呼び出すのは良いことです。


> ペン変数をpublic変数として定義する必要があり、
何故ですか?

Public として公開する必要があるのは処分手続きの部分だけであって、
処分対象の Pen そのものは、Private であったとしても構わないのでは。


> モジュール間で同じ同じ名称を使うことができません。
Module1 と Module2 の両方に、同じ名前の Pulic メンバーを設けることはできますよね?

Module 名は省略可能な名前空間であるかのように振舞われますので、
被った場合は、Module1.MemberName 形式で呼び出せるようになっています。

もちろんその分繁雑にはなるので、名前が被るような設計は望ましくわけですが、
「使うことができない」訳ではないはずです。たとえば Timer クラスは、
System.Windows.Forms 名前空間と System.Threading 名前空間の両方にありますが、
それぞれを区別して呼び出せるのと同じです。

ある意味、下記の状況にも似ているかな。

Partial Class Form1
 Private foo As Integer = 123
 Private Sub Method1()
   'ここでは「Me.foo」と書いても、単に「foo」と書いても同じこと
   MsgBox(foo)
 End Sub
 Private Sub Method2(foo As Integer)
   '「foo」の名が競合しているけれど、
   'どのオブジェクトのメンバーかを明示しているので、区別できる
   Me.foo = foo
 End Sub
End Class


> また、たくさんモジュールがあると、ペン変数の管理が面倒であるため、
> モジュールごとにdiposeしたいと考えています。

たくさんのモジュールですか。数が増えてくると、管理が繁雑になってきませんか?

拡張メソッドのように、Module でなければ管理できないものを除いては、
そもそも Module を多用しない方が良い気がするのですが……まぁ、実際のコードを
見たわけではないので、現時点では適切な設計かどうかの判断はできないですね。
機能単位に Namespace ステートメントで区切っておけば、競合もある程度防げますし。



> ペン変数はシャットダウン時にdiposeしないとメモリ内に残り続けるのでしょうか?
いいえ。プロセス(というか、アプリケーション ドメイン)がアンロードされた場合、
.NET Managed なオブジェクトはすべて解放されます。

Unmanaged なリソースな場合はその限りではありませんが、そのような場合、
Pen のように IDisposable として実装されるケースが殆どです。


> ということはクラスでないとできないということでしょうか?
といっても、そもそも Pen 自体がクラスなんですけれどね。

クラスで管理するにしても、クリーンアップの処理を
ファイナライザー(Sub Finalize)『だけ』に頼ることは避けてください。
ファイナライザーがあると、F-reachable キューに入ることでオブジェクトの寿命が
延びてしまうため、むしろガベージコレクトされにくくなってしまうためです。

だからこそ、IDisposable パターンな実装においては、IDisposable.Dispose メソッド内で
GC.SuppressFinalize(Me) を呼んでいるわけで。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -