前回触れた、BCCSkeltonのCANVASクラス類似のクラスをC#で作って、一応"Version 1.0"的な感じになりました。また、アプリのコードの中にそのクラスを定義する他、単独でコンパイルしてライブラリーにして使うテストもしました。(注)
注:前に書いたように、描画する背景ビットマップを"Canvas"(画版)プロパティとし、それ(及び描画用のペン、ブラシ、フォントおよび画像取り込み用のイメージ)を有する基底クラスを"Easel"(画架)しましたので、独立DLLとさせたときの名前空間とDLLのファイル名を"Atelier"(アトリエ)にしたのは必然でしょう!従って"using Atelier;"として、"Easel easel;"とオブジェクトを作り、イメージは"easel.Canvas;"となります。
さて、動作テストは(SDIスケルトン、MDIスケルトンと一緒に作った)DialogスケルトンにPictureBoxコントロールを貼り付けてテストしましたが、このコントロールは"Image"プロパティを持ち、WM_PAINTメッセージの際にこのImageを描画するように設計されています。
で、
気に掛ったのは、このImageプロパティの性格です。
C#という言語は、C++で当たり前のように使う(「危険な」)ポインターの利用を制限(注1)しておりますが、変数やオブジェクトの宣言は将に「ポインター的」であり、その変数やオブジェクトに(new付き、またはstring等では無しで)「初期化(実体となる所要メモリーをスタックに確保)」をしなければエラーになりますし、等号('=')で他の初期化済変数やオブジェクトを代入するとそれらに対する単なる「(自分には実体のない)参照」をするだけとなります。(注2)
注1:"unsafe"が無ければ使えない。
注2:C#で、
" SomeClass sc; //オブジェクトの宣言
sc = new SomeClass(); //初期化(メモリーの確保)→通常ガーベージコレクション処理となる
"
と書くのは、C++の
" SomeClass *sc; //オブジェクトポインターの宣言
sc = new SomeClass(); //初期化(メモリーの確保)→必ず"delete sc"が必要。
"
に酷似しています。
従って第1の疑問は、
Q1:PictureBox.Imageは単にポインター的変数なのか、実際にメモリーを確保して代入されたイメージをコピーするのか?
であり、
Q2:(仮に「実際にメモリーを確保」しているのなら)再代入(イメージの変更)の際、確保されたメモリー(元のイメージ)をDispose()でユーザーが開放すべきなのか
否か、ということです。(「開放すべき」でない場合はガーベージコレクションで開放されているはず。)
Q1の回答を得るべく、Form_Load(WM_CREATE)処理時に"picBox.Image = easel.Canvas;"とし、更に描画処理を行った後に"picBox.Image = easel.Canvas;"(画像の更新)としていたのを描画処理時のコードをコメントアウトしてみました。(「参照処理」であればそのまま更新されるはずであり、PictureBoxが独立したメモリーを持ってコピーしているのであれば、更新されない筈。)
結果は、...更新されませんでした。(PictureBox.Imageが独自の画像用メモリーを持っている。)
次にQ2についてwebをググったのですが、この問いに直接的に回答するものはなく(注)、Disposeをする派、しない派共に見受けられました。その為、自らいくつかのテストを行いました。
注:Visual Studio質問コーナーおよび「使用中のリソースをDisposeしてはいけません」
テスト1:"(初期代入済の)picBox.Image = easel.Canvas;"(画像の更新)のコードの前に"picBox.Image.Dispose();"を入れてみました。(コンパイル、動作に問題なければ、悪い処理ではない。)→結果、このプロパティの処理(Imageの"get; (Width)”処理)時、"有効な引数ではない"エラーに引っ掛かってしまいました。また、
Image oldimg = picBox.Image; //古いイメージデータの参照変数を用意しても(新たにnewしてメモリーを確保しても意味がない) easel.Canvas; //新しい画像データに入れ替えた後に
oldimg.Dispose
picBox.Image =(); //開放処理しようとしても、結局は新しいpicBox.Imageを参照していることになり、同じエラーとなります。
この為、「そもそも本当にPictureBox.Imageの画像変更や更新を行う際にユーザーによるDisposeが必要なのか?」と考え、タスクマネージャーを起動して連続して"picBox.Image = easel.Canvas;"を実行してみました。その結果、テストプログラムの所要メモリー(リソース消費も含むのだろう)は増加してゆきますが、放っておくと自然に減少(more probably than not, by garbage collection)することを確認しました。
なので、面倒なリソース解放処理はシステムに任せて、私は何もしないことにしました!
いいんだろうか?(汗;)