コンポーネントは、再利用できるコードをオブジェクトの形で提供します。オブジェクトを作成し、オブジェクトのプロパティやメソッドを呼び出すことによってコンポーネントのコードを使うアプリケーションは、クライアントと呼ばれます。クライアントは、使うコンポーネントと同じアセンブリ内に含まれている場合もあれば、それ以外の場所に存在する場合もあります。
ここで説明する作成手順は互いに関連しているため、各手順の実行順序が重要になります。
プロジェクトの作成
CDemoLib クラス ライブラリと CDemo コンポーネントを作成するには
- [ファイル] メニューの [新規作成] をクリックし、[プロジェクト] をクリックして [新しいプロジェクト] ダイアログ ボックスを表示します。[Visual J# プロジェクト] ボックスの一覧の [クラス ライブラリ] プロジェクト テンプレートをクリックし、[プロジェクト名] ボックスに「CDemoLib」と入力します。
ヒント 新しいプロジェクトを作成するときには、必ずプロジェクトの名前を指定します。これにより、ルート パッケージ、アセンブリ名、およびプロジェクト名が設定されます。また、既定のコンポーネントも適切なパッケージに含まれるようになります。
- ソリューション エクスプローラで [CDemoLib] を右クリックし、ショートカット メニューの [プロパティ] をクリックします。[既定のパッケージ] ボックスの内容が "CDemoLib" になっていることを確認します。
既定のパッケージは、アセンブリ内のコンポーネントの名前を限定するために使用されます。たとえば、CDemo という名前のコンポーネントが 2 つのアセンブリに含まれる場合は、CDemoLib.CDemo という形で目的の CDemo コンポーネントを指定できます。
[キャンセル] をクリックしてダイアログ ボックスを閉じます。
- [プロジェクト] メニューの [コンポーネントの追加] をクリックします。
- [新しい項目の追加] ダイアログ ボックスの [コンポーネント クラス] をクリックし、[ファイル名] ボックスに「CDemo.jsl」と入力します。[開く] をクリックします。
CDemo.jsl という名前のコンポーネントがクラス ライブラリに追加されます。
- ソリューション エクスプローラで CDemo.jsl を右クリックし、[コードの表示] をクリックします。コード エディタが表示されます。
public class CDemo のすぐ後ろに、extends System.ComponentModel.Component というコードが追加されていることを確認します。この部分は、CDemo クラスの継承元のクラスを示します。特に指定しない限り、コンポーネントはシステムによって提供される Component クラスを継承します。Component クラスには、デザイナを使う機能を含め、コンポーネントのための多くの機能が用意されています。
- ソリューション エクスプローラで Class1.jsl を右クリックし、[削除] をクリックします。これにより、クラス ライブラリに含まれる既定のクラスが削除されます。このクラスは、このチュートリアルでは使いません。
- [ファイル] メニューの [すべてを保存] をクリックしてプロジェクトを保存します。
コンストラクタと Finalize メソッドの追加
コンストラクタは、コンポーネントの初期化方法を制御します。Finalize メソッドは、コンポーネントの破棄方法を制御します。CDemo クラスのコンストラクタと Finalize メソッドには、存在する CDemo オブジェクトの現在の個数を保持するコードを記述します。
CDemo クラスのコンストラクタと Finalize メソッドのコードを追加するには
- コード エディタで、CDemo コンストラクタにメンバ変数を追加して、CDemo クラスのインスタンスの現在の個数と、各インスタンスの ID 番号を保持します。
// Visual J#
private long InstanceID;
private static long NextInstanceID = 0;
private static long ClassInstanceCount = 0;
ClassInstanceCount メンバ変数と NextInstanceID メンバ変数は static と宣言されるため、これらの変数はクラス レベルだけで存在します。これらのメンバにアクセスする CDemo のすべてのインスタンスは、メモリ上の同じ場所を使います。共有メンバは、コード内で CDemo クラスが最初に参照されたときに初期化されます。たとえば、CDemo オブジェクトが最初に作成されたときや、クラスの共有メンバの 1 つが最初にアクセスされたときなどに初期化されます。
- CDemo クラスの既定のコンストラクタである public CDemo() と public CDemo(System.ComponentModel.IContainer container) を探します。Visual J# では、すべてのコンストラクタがクラスと同じ名前になります。コンポーネントにはパラメータの異なるいくつかのコンストラクタを定義できますが、どのコンストラクタにもコンポーネントと同じ名前を付ける必要があります。
メモ クラスのインスタンスを作成できるクライアントは、クラスのコンストラクタのアクセス レベルによって決まります。
- public CDemo() に次のコードを追加します。これにより、新しい CDemo の作成時にインスタンス数がインクリメントされ、インスタンス ID 番号が設定されます。
メモ コードは、必ず InitializeComponent の呼び出しの後に追加してください。この呼び出しの時点で、含まれるコンポーネントがすべて初期化されます。
// Visual J#
InstanceID = NextInstanceID ++;
ClassInstanceCount ++;
メモ マルチスレッドについてよく理解すると、InstanceID の割り当てと NextInstanceID のインクリメントを分割できない操作にする必要があることがわかります。
- コンストラクタの末尾の後に次のメソッドを追加します。
// Visual J#
protected void Finalize()
{
ClassInstanceCount --;
}
メモリ マネージャは、CDemo オブジェクトによって占有されていたメモリを最後にクリアする直前に、Finalize を呼び出します。Finalize メソッドは、.NET Framework のすべての参照型のルートである Object に定義されています。Finalize をオーバーライドすると、コンポーネントがメモリから削除される直前にクリーンアップを実行できます。ただし、このチュートリアルで後述するように、リソースを早く解放した方が良い理由がいくつかあります。
クラスへのメソッドの追加
CDemo クラスに含まれているメンバを使うと、任意の時点でメモリ内に存在する CDemo オブジェクトの数をクライアントで取得できます。
CDemo のインスタンスの数を取得するメソッドを作成するには
- CDemo クラスに次のメソッド宣言を追加して、クライアントが CDemo のインスタンスの数を取得できるようにします。
// Visual J#
public static long getInstanceCount()
{
return ClassInstanceCount;
}
コンポーネントをビルドするには
コンポーネントのテスト
コンポーネントをテストするには、そのコンポーネントを使うプロジェクトが必要です。このプロジェクトは、F5 キーを押したときに最初に起動するプロジェクトとして設定する必要があります。
CDemoTest クライアント プロジェクトをソリューションのスタートアップ プロジェクトとして追加するには
- [ファイル] メニューの [プロジェクトの追加] をポイントし、[新しいプロジェクト] をクリックして [新しいプロジェクトの追加] ダイアログ ボックスを表示します。
- [Visual J# プロジェクト] ボックスの一覧の [Windows アプリケーション] プロジェクト テンプレートをクリックし、[プロジェクト名] ボックスに「CDemoTest」と入力します。次に、[OK] をクリックします。
- ソリューション エクスプローラで [CDemoTest] を右クリックし、ショートカット メニューの [スタートアップ プロジェクトに設定] をクリックします。
CDemo コンポーネントを使うには、クライアント テスト プロジェクトにクラス ライブラリ プロジェクトへの参照を追加する必要があります。参照を追加した後で、テスト アプリケーションに import ステートメントを追加すると、コンポーネントを簡単に使用できるようになります。
クラス ライブラリ プロジェクトへの参照を追加するには
- ソリューション エクスプローラで、[CDemoTest] のすぐ下にある [参照設定] ノードを右クリックし、ショートカット メニューの [参照の追加] をクリックします。
- [参照の追加] ダイアログ ボックスの [プロジェクト] タブをクリックします。
- [CDemoLib] クラス ライブラリ プロジェクトをダブルクリックして、[選択されたコンポーネント] ボックスの一覧に追加します。これにより、CDemoTest プロジェクトの [参照設定] ノードの下に CDemoLib が表示されます。[OK] をクリックして選択内容を受け入れます。
- ソリューション エクスプローラで Form1.jsl を右クリックし、ショートカット メニューの [コードの表示] をクリックします。
CDemoLib への参照を追加すると、CDemo コンポーネントの完全限定名 CDemoLib.CDemo を使用できるようになります。
import ステートメントを追加するには
オブジェクトの有効期間
CDemoTest プログラムでは、多数の CDemo オブジェクトを作成して解放することにより、.NET Framework のオブジェクトの有効期間を示します。
CDemo オブジェクトを作成および解放するコードを追加するには
- [Form1.jsl [デザイン]] をクリックしてデザイナに戻ります。
- ツールボックスの [Windows フォーム] タブから、ボタンとタイマを Form1 のデザイン画面にドラッグします。
非可視の Timer コンポーネントが、フォームの下の分割されたデザイン画面に表示されます。
- timer1 のアイコンをダブルクリックして、timer1 コンポーネントの Tick イベントに対するイベント処理メソッドを作成します。イベント処理メソッドに次のコードを追加します。
// Visual J#
this.set_Text("CDemo instances: " + CDemo.getInstanceCount());
タイマが時を刻むごとに、フォームのキャプションには現在の CDemo クラスのインスタンスの数が表示されます。クラス名は、共有 InstanceCount プロパティの修飾子として使用されます。共有メンバにアクセスするために CDemo のインスタンスを作成する必要はありません。
- Form1 のコンストラクタ (public Form1()) を探し、InitializeComponent() の呼び出しの後に次のコードを追加します。
// Visual J#
timer1.set_Enabled(true);
これにより、フォームが作成されるとすぐにタイマが起動されます。
- [Form1.jsl [デザイン]] タブをクリックしてデザイナに戻ります。
- Form1 上の Button をダブルクリックして、ボタンの Click イベントに対するイベント処理メソッドを作成します。イベント処理メソッドに次のコードを追加します。
// Visual J#
CDemo cd;
int ct;
for (ct = 0; ct < 1000; ct++)
{
cd = new CDemo();
}
このコードは理解しにくいかもしれません。CDemo の各インスタンスが作成されるたびに、前のインスタンスが解放されます。for ループが終了すると、CDemo のインスタンスが 1 つだけ残ります。イベント処理メソッドが終了すると、変数 cd がスコープ外になるため、そのインスタンスも解放されます。
ただし、実際の処理は厳密にこのとおりには行われません。
CDemoTest プロジェクトと CDemo プロジェクトを実行してデバッグするには
- F5 キーを押してソリューションを起動します。
クライアント プロジェクトが起動し、Form1 が表示されます。フォームのキャプションが "CDemo instances: 0" となっていることを確認します。
- ボタンをクリックします。フォームのキャプションが "CDemo instances: 1000" となります。
CDemo のインスタンスは、ボタンの Click イベント処理プロシージャが終了するまでにすべて解放されています。これらはなぜ終了されなかったのでしょうか。簡単に言うと、メモリ マネージャがバックグラウンドでオブジェクトを終了させる優先順位が低いためです。優先順位は、システムがメモリ不足になった場合にだけ高くなります。このようなガベージ コレクション スキームを使うと、オブジェクトを高速に割り当てることができます。
- ボタンをさらに数回クリックしてキャプションを確認します。ある時点で、インスタンスの数が突然少なくなります。これは、メモリ マネージャがいくつかのオブジェクトのメモリをクリアしたことを意味します。
メモ 10 回を超えてクリックしても CDemo のインスタンス数が減らない場合は、メモリの使用量を増やすようにコードの調整が必要になる場合があります。フォームを閉じて開発環境に戻り、for ループの繰り返し回数を 10000 に増やしてから、もう一度プロジェクトを実行します。
- 手順 3. を繰り返します。今度はインスタンス数がさらに減り、メモリ マネージャはより多くのオブジェクトを終了します。
実際には、手順 3. を繰り返すたびに、メモリ マネージャでの処理が実行されるより早く、より多くの CDemo オブジェクトを割り当てられるようになります。これは、Visual Studio のより多くの部分がスワップ アウトされ、CDemo のインスタンス用に多くのメモリ領域が残されるためです。
- フォームを閉じて開発環境に戻ります。
参照
コンポーネントによるプログラミング | コンポーネントおよびコントロール作成のチュートリアル