.NET でのコンポーネントの作成
Microsoft .NET へのアップグレード
Michael Groh
PC Productivity Solutions
February 2002
日本語版最終更新日 2002 年 9 月 19 日
要約: オブジェクト指向プログラミング原理をベースにした、他のアプリケーションで使用される単純なクラスよりもはるかに高度な機能を備えているコンポーネントを Microsoft .NET で作成する方法について解説します。
目標
- Microsoft® .NET コンポーネント アーキテクチャを理解する。
- .NET コンポーネントの作成方法を学ぶ。
- Microsoft Visual Basic® .NET でインプロセス コンポーネントとアウトプロセス コンポーネントの両方を作成する。
- .NET オブジェクトがインターフェイスを公開する方法を理解する。
前提条件
- いずれかのバージョンの Visual Basic でアプリケーションを作成した経験があること。
- オブジェクト指向プログラミング (OOP) の基本的な概念を理解していること。
- .NET でのクラスの作成方法を知っていること。
- DLL の概念を知っていること。
- Web サービスの概念を知っていること。
目次
.NET コンポーネントについて
.NET クラスとコンポーネント
エラー処理の実装
Visual Studio .NET 環境での複数の Visual Basic プロジェクトの使用
コンポーネントへのコンストラクタの追加
アセンブリ情報の更新
名前空間の指定
Visual Basic .NET での COM コンポーネントの使用
Visual Basic 6.0 との違い
要約
.NET コンポーネントについて
Microsoft .NET アプリケーションはコンポーネントを組み合わせて作成されます。すべての.NET オブジェクトは、プロパティ、メソッド、およびイベントなどの重要な属性を公開しています。これらの属性はオブジェクト指向プログラミングの基盤となっています。
Visual Basic .NET オブジェクトを設計するプログラマは、他のプログラマがアプリケーションのサービスを利用するために必要となるインターフェイス (すなわちプロパティ、メソッド、およびイベント) を実装する責任も負っています。開発時間の多くは、アプリケーションが公開する、またアプリケーションが使用するオブジェクトの設計と、そのようなオブジェクトとコンポーネントを定義するコードの作成に費やされることになります。
一般に、単純な.NET オブジェクト指向プログラミングは、クラスを作成し、クラスに必要なプロパティ、メソッド、およびイベントを追加し、そのクラスをさまざまなアプリケーションに追加することによって行います。コンポーネント ベースの開発は、この基本的なコンセプトをさらに高いレベルで実現します。.NET で作成するコンポーネントはオブジェクト指向プログラミングの原理をベースにしていますが、複数のアプリケーションで使用される単純なクラスよりもはるかに高度な機能を備えています。
.NET コンポーネントとは?
コンポーネントは、.NET プロジェクトでビルドされる特殊なタイプの実行可能ファイルです。コンパイルされたコンポーネントは、一般にそのコンポーネントが提供しているサービスを必要とするアプリケーションから参照されます。多くの.NET Web 環境では、コンポーネントは Web サーバー上で実行され、サーバー上で動作している Web サービスに対してデータやその他のサービス (セキュリティ、通信、グラフィックスなど) を提供します。Windows フォーム アプリケーションでは、.NET コンポーネントは Web サーバーと同じ役割を、より小さいスケールで果たします。
.NET コンポーネントはコンシューマ アプリケーション (一般にクライアント アプリケーションと呼ばれます) からアクセスされるプログラミング可能なインターフェイスを提供します。コンポーネント インターフェイスは、コンポーネントに含まれているクラスが公開しているいくつかのプロパティ、メソッド、およびイベントから構成されています。言い換えると、コンポーネントは、そのコンポーネントが提供するサービスをサポートしている、コンパイル済みのクラスのセットです。これらのクラスは、コンポーネントのインターフェイスを構成するプロパティ、メソッド、およびイベントを通して自らのサービスを公開します。
単純な.NET オブジェクト指向プログラミングは、クラスを作成し、そのクラスに必要なプロパティ、メソッド、およびイベントを追加し、クラスをさまざまなアプリケーションに追加するという程度のことしか行いません。一方、.NET コンポーネントは、.DLL (ダイナミック リンク ライブラリ) の拡張子を持つコンパイル済みのクラス モジュールです。.NET コンポーネントは実行時に起動され、メモリにロードされて、コンシューマ アプリケーションから利用できる状態になります。これらの.NET コンポーネントは一般に独立した.NET プロジェクトとしてビルドおよびテストされ、必ずしも他のプロジェクトに属しているわけではありません。.NET DLL にコンパイルされたコンポーネントは、複数の.NET アプリケーションにプラグイン サービス プロバイダとして追加することができます。
1 つの.NET DLL コンポーネントは複数のクラスを含むことができます。つまり、個々の DLL は 1 つのクラスを公開することも、複数のクラスを公開することもあります。たとえば、リモート データ アクセスをサポートする.NET DLL を作成する場合、その DLL はデータベース用のクラスと、DLL が生成する各種のデータセット用のクラスを別々に公開しなくてはならないでしょう。あるいは、1 つの DLL で複数のアプリケーションのエラー処理をサポートする場合、その DLL はコンシューマ アプリケーションに必要なすべてのエラー処理を実行する 1 つの ErrorHandler クラスを公開することになります。
注 コンポーネントはさまざまな物を指す言葉として使われます。この用語の定義の詳細については、MSDN の「.NET へのアップグレード」の他の記事も参照してください。
コンポーネントがプロセス内で実行されるということの意味は?
すべての Microsoft Windows® アプリケーションは、コンピュータのメモリ内で動作し、ディスク スペース、ネットワーキング サービス、およびグラフィックス機能といったコンピュータのリソースを使用します。Windows がマルチタスキング オペレーティング システムであるとは、複数のアプリケーションがコンピュータのメモリやその他のリソースを同時に共有するということを意味しています。
Windows は、個々のアプリケーションとそのアプリケーションが必要とするメモリを、1 つのプロセスとして管理します。Windows アプリケーションとそのデータが占有するメモリは、アプリケーションのプロセス空間と呼ばれます。Windows が行う重要な仕事には、アプリケーションが占有するプロセス空間がオーバーラップしないようにし、各プロセスに必要に応じてメモリを提供することがあります。
状況によっては、Windows は複数のアプリケーション間でのプロセス空間の共有を許すことがあります。これは特に、アプリケーション間で共有しなくてはならないデータやサービス (ネットワーキング サービスなど) に当てはまります。それ以外の状況では、アプリケーションが占有するメモリは、そのプロセス空間内で実行されている EXE のみによって所有されています。
Microsoft Word や Microsoft Excel などの多くのアプリケーションは、数十または数百種類の機能をサポートしています。Microsoft は、これらのアプリケーションを巨大な 1 つのファイルとして配布する代わりに、Word と Excel がサポートしている基本的な機能を複数の実行可能ファイルに分割しました。メイン プログラムは.EXE という拡張子を持ちますが、その他の大部分の実行可能な部分は.DLL で終わるファイルに格納されています。
Word や Excel が DLL に含まれている機能 (スペル チェッカーや再計算エンジンなど) を必要とするとき、Windows はその DLL をメイン アプリケーションが占有しているプロセス空間にロードします。その後、Windows はメイン プログラムと DLL に含まれている実行可能コードを、1 つのプロセスとして管理します。DLL は、他のアプリケーションによって占有されているプロセス空間の中で実行されるため、インプロセス リソースと呼ばれます。
これ以外に、リソースがインプロセスにロードされない状況があります。たとえば、Word がドキュメントを印刷する必要があるとき、Word は Windows に対し、特定のプリンタ ドライバをロードするように要求します。このプリンタ ドライバは他のアプリケーションから要求されることもあるので、Windows は複数のアプリケーションからアクセスできるように、そのドライバをアウトプロセス サービスとしてロードします。これはまた、Windows がドライバの複数のコピーをメモリにロードする必要がないということも意味しています。
インプロセス コンポーネント
.NET においては、DLL として作成されたコンポーネントはホスト アプリケーションのプロセス空間の中で実行され、メモリとプロセッサ時間をホスト アプリケーションと共有します。実行時には、(ホスト アプリケーションのアセンブリに含まれており、そのマニフェストによって参照される) コンポーネントがディスクからロードされ、ホスト アプリケーションのプロセス空間に追加されます。コンポーネントとそのホストの間の通信を仲介するためにリモート プロシージャ呼び出しは生成されないので、プロパティ値の設定と読み出し、メソッドの呼び出し、およびコンポーネントが生成したイベントへの応答はきわめて高速に行われます。
アウトプロセス コンポーネント
これとは別のアーキテクチャでは、サーバー アプリケーションが、クライアント アプリケーションのプロセス空間の外の独立したプロセスとして実行されます。これらのサーバー アプリケーションは、(必ずではないにせよ) 一般に EXE のファイル名拡張子を持ちます。Windows がアウトプロセス コンポーネントをロードすると、そのコンポーネントのために独立したプロセス空間が作成され、Windows はアウトプロセス コンポーネントのリソース要件をクライアント アプリケーションのリソース要件とは独立に管理します。Windows はサーバー アプリケーション (すなわちコンポーネント) とクライアント (コンシューマ) の間の対話を、両者の間でメッセージを受け渡すことによって仲介します。
Visual Basic 6.0 と Visual Basic .NET でのコンポーネントのインプロセスとアウトプロセスでの実行の比較
インプロセスとアウトプロセスのアプリケーション アーキテクチャの間には、いくつかの大きな違いがあります。
- インプロセス アプリケーションは、リモート プロシージャ呼び出しが不要なため、より高速に動作します。クライアント アプリケーションは、Windows による対話の仲介に頼らずに、コンポーネントに直接アクセスすることができます。
- アウトプロセス アプリケーションは、場合によっては、インプロセス コンポーネントから作られたアプリケーションよりも高い安定性を示します。アウトプロセス コンポーネントがクラッシュした場合でも、コンシューマ アプリケーションが道連れになることはありません。一方、インプロセス コンポーネントが実行を停止した場合には、コンシューマも一緒にクラッシュすることが珍しくありません。
- アウトプロセス コンポーネントは、多数のコンシューマ アプリケーションの間で簡単に共有できます。共有可能なリソースとしてコンパイルされた場合、Windows はアウトプロセス コンポーネントのコピーを 1 つだけロードし、要求してきた任意の数のコンシューマに対して提供します。ただし、多数のコンシューマが同時にコンポーネントを要求した場合には、パフォーマンスが大幅に低下する可能性があります。
.NET クラスとコンポーネント
この記事で作成するサンプルは特に高度なものではありませんが、.NET におけるクラスとコンポーネントの開発原理の効果的なデモンストレーションとなっています。まず最初に、単純な.NET クラスを作成します。クラスを作成したら、同じコードを使ってコンポーネントを作成し、このコンポーネントを小さな.NET アプリケーションに組み込みます。
分散データベース システムの典型的な要件として、リモート ロケーションで行われた更新を同期させ、調整するというものがあります。.NET にホスティングされたデータベース アプリケーションでは、同じレコードが複数のサイトで更新され、保管のためにサーバーにサブミットされることがあります。また、複数のサイトで似たようなレコードが作成され、処理のためにサーバーに送信されることもあります。このようなケースでは、新しいレコードを古いレコードと区別して扱えるように、レコードがいつ更新または作成されたのかを正確に知る必要があるでしょう。
ほとんどのケースでは、アプリケーションはデータの変更や追加が行われるたびに、データベース レコードにタイムスタンプを割り当てます。サーバーは 1 つのレコードのタイムスタンプを別のレコードのタイムスタンプと比較して、それに応じてレコードの処理を行うことができます。ただし、データが異なるタイムゾーンの中で更新されていた場合には、タイムスタンプの基準時刻を適切に使用することが重要となります。これは通常は、データ入力のローカル時刻ではなく、サーバー コンピュータの時刻をタイムスタンプとして使用することによって解決されます。
これは.NET コンポーネントにぴったりの機能だと言えるでしょう。.NET サーバーは、自分の時刻を、任意のコンシューマ アプリケーションから読み取って使用できる Web サービス コンポーネントとして公開することができます。サーバー時刻コンポーネントが Web サービスとして提供されていれば、地理的に離れたロケーションで行われるデータ変更の調整が楽になります。
Visual Basic 6.0 のクラスと.NET のクラスの大きな違いの 1 つは、個々の Visual Basic 6.0 クラス モジュール (ファイル) は 1 つのクラスしか含んでいないという点にあります。つまり、多数のクラスを公開するプロジェクトは、多数のクラス モジュール (ファイル) を含んでいるということになります。
.NET では、クラスはコード中のほぼ任意の場所に作成することができます。つまり、.NET アプリケーションのファイルは 1 つまたは複数のクラスを含むことができます。.NET コード モジュールの中の個々のクラスは、モジュール内の Public Class..End Class コード ブロックによって定義されます。
このアーキテクチャのおかげで、.NET プロジェクト内で開発されたクラスは簡単に論理的なグループに分類できるようになっています。たとえば、前に述べたデータ アクセス コンポーネントでは、すべての基本的なデータ アクセス クラス (データベースの識別とログインなど) を 1 つのモジュールにまとめ、データセットの作成と操作に関するすべての機能を第 2 のモジュールにまとめることができます。このように、個々のモジュールが複数のクラスをサポートしているため、それぞれが 1 つのクラスを含んでいる多数のモジュールを扱うよりもプロジェクト管理が簡単になります。
しかし、タイムスタンプの例は、これとはいくぶん異なります。ここで必要となるのは、.NET サーバーが内部的な日付と時刻を、コンポーネントのプロパティとして公開するということだけです。このような単純なコンポーネントのコードを複数のクラス モジュールに分割する必要はないでしょう。
クラスの作成
ホスト コンピュータの日付と時刻を返す単純なクラス モジュールを作成するためのステップを以下に示します。
- Visual Studio .NET を起動し、新規の Windows アプリケーション プロジェクトを開きます。
- プロジェクトの既定の Windows フォームを無視し、[プロジェクト] メニューの [クラスの追加] をクリックして、プロジェクトに新しいファイルを追加します。
- 生成された Public Class の名前を Class1 から ServerTime に変更します。
- 次のコードを入力して、ServerTime クラスを定義します。
Public Class ServerTime
Private mdtTime As DateTime
ReadOnly Property TimeStamp() As String
Get
mdtTime = Now()
Return CStr(mdtTime)
End Get
End Property
End Class
このクラスのプライベート変数 mdtTime は必須ではありません。単に現在の日付と時刻を、mdtTime 変数に代入せずに返すことも可能です。しかし、プログラミング プロジェクトは当初の仕様から離れて拡大することが多いので、将来、ServerTime クラスの中の複数のプロパティやメソッドから共有されるモジュール レベルの変数が必要にならないとも限りません。
次に、新規のプロジェクトで自動的に作成された Windows フォームを使って、ServerTime クラスの動作をテストします。次の操作を行って、ServerTime クラスのオブジェクトを作成し、Windows フォームから使用します。
- クラス モジュールのコンシューマとしての役割を強調するために、フォームの名前を Form1 から frmConsumer に変更します。
- Windows フォームに TextBox を追加し、txtServerTime という名前を付けます。
- Text プロパティの文字列を削除して、空白にします。
- Windows フォームにボタンを追加し、btnGetServerTime という名前を付けます。
- このボタンの Text プロパティを Get Server Time に設定します。
- ボタンをダブルクリックして、Windows フォームの背後に次のコードを追加します (コードを読みやすくするために、イベント プロシージャの宣言に継続文字を付けています)。
Private Sub btnGetServerTime_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnGetServerTime.Click
Dim st As ServerTime
st = New ServerTime()
txtServerTime.Text = st.TimeStamp
End Sub
ServerTime クラスはこのプロジェクトのアセンブリに含まれているので、コンシューマ フォームのコード モジュールから参照を行う必要はありません。.NET は ServerTime クラスを発見し、クラスに含まれている情報から st オブジェクト変数をインスタンス作成することができます。
このコードをボタンの Click イベント プロシージャに追加しておくと、ボタンがクリックされるたびに、txtServerTime に現在の日付と時刻が書き込まれます。
演習
このアプリケーションをテストして、コードを正しく入力しているかどうかを確認します。
- [F5] キーを押してアプリケーションを実行します。
- [Get Server Time] をクリックすると、テキスト ボックスに日付と時刻が表示されるはずです。
コンポーネントの作成
前のセクションでは、現在の日付と時刻を返す単純なクラス モジュールを作成し、このクラス モジュールを.NET Windows フォームの中でテストしました。次の操作を行うと、前のクラス モジュールの例で使用したコードから、.NET DLL コンポーネントを作成することができます。
- Visual Studio .NET を起動し、新規のクラス ライブラリ プロジェクトを開きます。[新しいプロジェクト] ダイアログ ボックスで、プロジェクトに ServerTime という名前を付けます。
- クラスの名前を Class1 から ServerTime に変更します。
- 前の例で作成した ServerTime クラス モジュールのコードを新しい ServerTime クラス モジュールにコピーするか、次のコード全体を新しい ServerTime クラス モジュールに入力します。
Public Class ServerTime
Private mdtTime As DateTime
ReadOnly Property TimeStamp() As String
Get
mdtTime = Now()
Return CStr(mdtTime)
End Get
End Property
End Class
その後、[デバッグ] メニューの [ソリューションのビルド] をクリックするか、[Ctrl+Shift+B] のキーの組み合わせを使用して、ServerTime クラスをコンパイルします。
ビルド コマンドの結果として生成された DLL は、.NET プロジェクト ディレクトリのすぐ下の\bin ディレクトリに格納されます。既定の設定では、DLL はコンポーネント プロジェクトと同じ名前を持ちます。たとえば、[新しいプロジェクト] ダイアログでプロジェクトに TimeStamp という名前を付けた場合、プロジェクトが生成する DLL は TimeStamp.DLL という名前になります。この名前は、プロジェクトに含まれるクラスの既定の名前空間名にもなります。
このドキュメントのステップに従っていれば、プロジェクトの名前は ServerTime になっているはずです。また、プロジェクト内の唯一のクラスにも ServerTime という名前を付けています。このため、DLL 名は ServerTime.DLL になり、この DLL のコンシューマ アプリケーションは、このクラスのオブジェクトを作成するときに ServerTime.ServerTime を参照することになります。
DLL コンシューマ アプリケーションの作成
DLL プロジェクトのコンパイルを終えると、そのサービスは任意の Windows フォームまたは Web フォーム.NET アプリケーションから利用できるようになります。このセクションでは、ServerTime クラスを使ってコンピュータの日付と時刻を取得する単純な Windows フォーム コンシューマ アプリケーションを作成します。
次の操作を行って、コンシューマ アプリケーションを作成します。
- Visual Studio .NET を起動し、新しいプロジェクトの種類として Windows アプリケーションを選択し、プロジェクトに DLLConsumer1 という名前を付けます。
- 既定の Windows フォームの Name プロパティを frmConsumer に設定します。
- 既定の Windows フォームにボタン コントロールを追加し、btnGetServerTime という名前を付けます。
- フォームに TextBox を追加し、txtServerTime という名前を付けます。
このフォームがコンポーネント サービスを使用できるように、ServerTime DLL への参照を設定する必要があります。このためには次の操作を行います。
- 図 1 に示す [参照の追加] ダイアログ ボックスを開くために、[プロジェクト] メニューの [参照の追加] をクリックします。
図 1. [参照の追加] ダイアログ ボックスの [.NET] タブ
- [プロジェクト] タブをクリックし、[参照] をクリックして、前のセクションで作成したコンポーネント DLL を探します (図 2 を参照)。
図 2. DLL 参照の選択
- ServerTime.DLL ファイルを選択し、[開く] をクリックし、[OK] をクリックします。
ソリューション エクスプローラは、図 3 に示すように、アプリケーションに追加された参照として ServerTime コンポーネントを表示するようになります。これで、コンシューマ アプリケーションは、このコンポーネントのすべてのクラスのプロパティ、メソッド、およびイベントを利用できるようになりました。

図 3. ソリューション エクスプローラで現在のすべての参照が表示されている様子
btnGetServerTime の Click イベントに次のコードを追加します。
Private Sub btnGetServerTime_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnGetServerTime.Click
Dim st As ServerTime
st = New ServerTime()
txtServerTime.Text = st.TimeStamp
End Sub
このコードは、前に ServerTime クラス モジュールの動作のテストに使用したコードと同じものです。現実の世界では、Web フォームまたは Windows フォームは、ServerTime.TimeStamp プロパティをもとに、DataSet オブジェクトの中の新しいまたは更新されたレコードのタイムスタンプ フィールドを更新するという使い方をすることになるでしょう。ServerTime DLL が実際に (LAN または Web ベースの) サーバー コンピュータ上で実行されていた場合、TimeStamp プロパティが返す時刻はサーバー上の実際の時刻を反映しています。つまり、ローカル コンピュータが別のタイムゾーンにあったり、時刻が間違って設定されていたりした場合でも、そのサーバーを使用している他のコンピュータと同じ基準時刻を得ることができます。
上のコード例は、次のように書くこともできます。
Private Sub btnGetServerTime_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnGetServerTime.Click
Dim st As New ServerTime
txtServerTime.Text = st.TimeStamp
End Sub
この例では、st オブジェクト変数の宣言とインスタンス作成を 1 つのステップで行っています。開発者によっては、入力の手間を省くために、宣言とインスタンス作成をつねに一緒に行う人がいます。一方、オブジェクトの宣言をしておいて、アプリケーションでそのオブジェクトが本当に必要になったときにインスタンス作成を行う人もいます。
ほとんどのケースでは、インスタンス作成を早く行っても後で行ってもまったく違いがありません。しかし状況によっては、オブジェクトのインスタンス作成は、アプリケーションが本当に必要としたときにのみ行う方がいいことがあります。たとえば、このペーパーで取り上げている ServerTime コンポーネントを考えてみましょう。アプリケーションの開発者は、正しいサーバー時刻を知る必要が生じたとき、つまりユーザーがデータベース内の情報を追加または更新したときにのみインスタンス作成を行うようにすることができます。分散アプリケーションの目標の 1 つは、サーバーへのトリップの回数を最小限に抑えることです。コンシューマ アプリケーションが実際に必要とするまで、ServerTime オブジェクトをインスタンス生成してサーバーに負荷を掛ける必要はありません。
エラー処理の実装
分散アプリケーションは高い信頼性を備えていなくてはなりません。エラーや問題のせいで、.NET Web サービスなどのサーバー ベース アプリケーションが停止してはなりません。.NET DLL はホスト アプリケーションと同じプロセス空間の中で実行されるので、.NET DLL 内で処理されない例外があると、Web サービス全体がクラッシュし、その Web サービスを使用しているすべてのユーザーに影響が及ぶ可能性があります。さらに悪いことに、サーバー サイドのクラッシュはデータベース エンジンの活動に影響を及ぼし、レコードをロックされた状態や不定の状態のまま残しかねません。
このような理由から、すべての.NET コンポーネントには適切なエラー処理を追加する必要があります。
次のコードは、ServerTime クラスの TimeStamp プロパティに効果的なエラー処理を追加した様子を示しています。Try、Catch、および End Try ステートメントの使い方に注目してください。
ReadOnly Property TimeStamp() As String
Get
Try
mdtTime = Now()
Return CStr(mdtTime)
Catch e As Exception
'例外を、コンシューマで処理するために
'返す
Throw e
End Try
End Get
End Property
Try..End Try ステートメントは、プロパティのすべてのロジックをラップし、プロパティのコードが生成したすべてのエラーをキャッチするためのエラー トラップを提供しています。クラス内のすべてのプロパティは独自の Try..End Try ブロックを持たなくてはならず、何か問題が生じた場合には、コンシューマ アプリケーションに対して例外をスローするべきです。その後のエラー処理をどのように行うかは、コンシューマ アプリケーションの自由です。
次のコードは、SystemTime コンポーネントの中でのより高度なエラー処理のアプローチを示しています。
ReadOnly Property TimeStamp() As String
Get
Try
mTime = Now()
Return CStr(mTime)
Catch e As Exception
'例外を、コンシューマで処理するために
'返す
Throw e
End Try
End Get
End Property
この例では、Catch ブロックはコンシューマ アプリケーションに Exception オブジェクト (e) を返しています。Exception オブジェクトは、発生した例外に関する、コンシューマ アプリケーションにとって有用かもしれない情報を含んでいます。
Visual Basic .NET のエラー処理は、Visual Basic 6.0 のエラー処理と大きく異なっています。Visual Basic .NET の Try..End Try ブロックは「構造化エラー処理」と呼ばれ、Visual Basic 6.0 の On Error ステートメントと比べると格段に改善されています。
Visual Basic 6.0 では、エラーが発生すると、処理はプロシージャの別の部分に無条件にリダイレクトされていました。このため、例外が起こったときのアプリケーションのパスを正確に判断するのが難しくなることがありました。Visual Basic 6.0 の例外処理の一般的なアプローチは、VBA コンパイラによって厳密に適用されておらず、プログラマはかなり自由に独自のエラー処理アプローチを採用することができました。このため、Visual Basic 6.0 プロジェクトのエラー処理にはさまざまなスタイルがあり、混乱が生じていました。
Visual Basic .NET では、コンポーネントがスローした例外は、次のコードに示すように、コンシューマ アプリケーションの中の Try..End Try ブロックによってキャッチされます。
Private Sub btnGetServerTime_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnGetServerTime.Click
Dim st As New ServerTime
Try
txtServerTime.Text = st.TimeStamp
Catch e As Exception
MessageBox.Show(e.Message)
End Try
End Sub
これもまた、.NET と Visual Basic 6.0 の違いの 1 つです。.NET アプリケーションのコンポーネントはコンシューマ アプリケーションのロジックに緊密に結びつけられており、コンシューマ アプリケーションをコンポーネントと統合したときに生じる問題を、実際に実行する前に発見できることも少なくありません。
Visual Basic .NET は後方互換性のために古い On Error ステートメントをサポートしていますが、Visual Basic .NET プロジェクトでは Try..End Try の構造化エラー処理を採用するべきです。Visual Basic .NET のコードに Try..End Try ブロックを追加することで、古い On Error GoTo ステートメントよりもはるかにスムーズにエラー処理を行えることがわかるはずです。
Visual Studio .NET 環境での複数の Visual Basic プロジェクトの使用
上では、コンシューマ アプリケーションを作成して、コンシューマ フォームとクラスの両方が同じプロジェクトに含まれている状態で ServerTime クラスのテストを行いました。その後、別のコンシューマ アプリケーションを作成して、ServerTime.DLL コンポーネントに含まれているコンパイル済みバージョンのクラスをテストしました。これらの多様なプロジェクトは、Visual Basic .NET 言語に基づく.NET コンポーネントの開発を進めていくと、混乱と効率低下の原因になりかねません。Visual Basic 6.0 では、コードがどのように連動しているのかを見るためには、さまざまなコンシューマ プロジェクトとコンポーネント プロジェクトの間で行き来する必要がありました。
これよりも効率的なアプローチは、コンシューマ プロジェクトを Visual Studio .NET ソリューションの一部として取り込むことです。この統合プロジェクトでは、必要に応じてコンポーネント プロジェクトの変更と再コンパイルを行いながら、コンポーネントの呼び出しと実行を行うことができます。Visual Studio .NET は、Visual Studio 環境に複数のプロジェクトを同時に含んでいるソリューションの概念をサポートしています。Visual Studio ソリューション内の個々のコンポーネントは、同じソリューション内の他のプロジェクトからは独立に編集し、コンパイルすることができます。
注 このドキュメントでは扱っていませんが、.NET ソリューションには C# や C++ などの他の Visual Studio .NET 言語で書かれたプロジェクトを含めることができます。これにより、Visual Basic 以外の言語スキルを持っている開発者が作成したプロジェクトを簡単に組み込むことができます。
ソリューションの一部としてのコンシューマ プロジェクトの作成
次の操作を行って、コンポーネント プロジェクトのソリューションにコンシューマ プロジェクトを追加します。
- まだ開かれている場合には、コンポーネント コンシューマ アプリケーションを閉じ、DLL コンポーネント プロジェクトを開きます (ServerTime という名前になっているはずです)。
- [ファイル] メニューの [プロジェクトの追加] をクリックし、[既存のプロジェクト] をクリックして、[既存プロジェクトの追加] ダイアログ ボックスを開きます。
- [既存プロジェクトの追加] ダイアログ ボックスを使用して、コンシューマ プロジェクト ファイル (.vbproj の拡張子) を探し、[開く] をクリックしてコンポーネント ソリューションに追加します。
コンシューマ プロジェクトが追加されると、ソリューション エクスプローラは図 4 のように両方のプロジェクトを表示するようになります。ServerTime プロジェクトは太字で、ClassConsumer プロジェクトは通常のテキストとして表示されていることに注意してください。

図 4. ソリューション エクスプローラはソリューションに含まれているすべてのプロジェクトを表示し、スタートアップ プロジェクトの名前は太字で表示される
太字のテキストは、ServerTime プロジェクトがソリューションのスタートアップ プロジェクトであることを示しています。実際、この時点で [F5] キーを押すと、「クラス ライブラリの出力タイプを持つプロジェクトを直接起動することはできません」というエラー メッセージが表示されます。これは、コンパイル済みのクラス ライブラリ (iDLL) を独立したアプリケーションとして実行することはできないという意味です。
[ソリューション エクスプローラ] ウィンドウで、DLLConsumer1 プロジェクトを右クリックし、コンテキスト メニューから [スタートアップ プロジェクトに設定] を選択して、これをスタートアップ プロジェクトに設定します。

図 5. DLLConsumer1 がスタートアップ プロジェクト
この時点で [F5] キーを押すと、Visual Studio .NET はコンシューマ アプリケーションを起動します。このアプリケーションは ServerTime.DLL を参照しています。.NET は最新のコンパイル済み DLL をロードすることに注意してください。コンポーネントのコードに変更を加えた場合には、コンポーネントを再コンパイルしておかないと、コンシューマ アプリケーションからは変更点は見えません。
Visual Studio .NET に複数のプロジェクトがロードされているとき、[ビルド] メニューには、現在 [ソリューション エクスプローラ] ウィンドウで選択されているプロジェクトのための [ビルド] コマンドと、すべてのプロジェクトを 1 ステップでコンパイルする [ソリューションのビルド] コマンドが表示されます (図 6 を参照)。

図 6. ソリューション エクスプローラに複数のプロジェクトが含まれている場合、[ビルド] メニューには、すべてのプロジェクトをビルドするためのコマンドが表示される
[ソリューション エクスプローラ] ウィンドウで DLLConsumer1 プロジェクトが選択されていた場合には、[ServerTime のビルド] メニューの代わりに [DLLConsumer1 のビルド] が表示されます。
コンポーネントへのコンストラクタの追加
Visual Studio .NET コンポーネントのエキサイティングな機能の 1 つとして、オブジェクトのインスタンス作成時に引数を渡すことができます。これは、オブジェクトの作成時に、オブジェクトを特定の値に初期化したい場合に重要となります。
再びタイムスタンプ コンポーネントの例を考えてみましょう。コンポーネントのコンシューマはサーバー A からデータを取得する必要があり、別のコンシューマはサーバー B からデータを取得する必要があるとします。Visual Basic 6.0 では、サーバー名を変更するためには、オブジェクトが宣言されてインスタンス作成されるまで待ち、サーバー名をオブジェクトのプロパティとして設定する必要がありました。
ケースによっては、インスタンス作成が行われるまで待つよりも、オブジェクトの作成時にメモリ内でサーバー名を設定する方が効率的です。たとえば、そのサーバーは利用不可能な状態になっているかもしれません。このような場合には、オブジェクトをインスタンス作成し、サーバー名の値を設定し、プロパティを読み取ってサーバーが利用可能になっているかどうかを調べるという手順を踏むよりも、インスタンス作成のステップを失敗させる (オブジェクトの値を Nothing にする) 方が論理的です。
Visual Studio .NET では、コンポーネントのクラス モジュールに New() メソッドを追加することで、オブジェクト コンストラクタに引数を渡すことができます。この New() メソッドは、このクラスから作成されるオブジェクトのコンストラクタとなります。
次に、クラス モジュールに New() コンストラクタ メソッドを追加した様子を示します。New() への引数として渡されるパラメータに注目してください。
Public Class ServerTime
Public Enum tsFormat
fLong = 0
fShort = 1
fMedium = 2
End Enum
Private mdtTime As DateTime
Private mstrFormat As String
Public Sub New( _
Optional ByVal TimeStampFormat _
As tsFormat = tsFormat.fShort)
Select Case TimeStampFormat
Case tsFormat.fShort
mstrFormat = "Short Date"
Case tsFormat.fMedium
mstrFormat = "Medium Date"
Case tsFormat.fLong
mstrFormat = "Long Date"
Case Else
mstrFormat = "Short Date"
End Select
End Sub
ReadOnly Property TimeStamp() As String
Get
Try
mTime = Now()
Return Format(mTime, mstrFormat)
Catch e As Exception
'例外を、処理のためにコンシューマに
'返す
Throw e
End Try
End Get
End Property
End Class
この例のコードは、列挙子を使って、tsFormat 引数が受け付ける値を指定しています。プログラマが作成するプロパティは、きわめて特殊な値を必要とすることが少なくありません。他の開発者がこれらの値を推測しなくても済むように、Microsoft IntelliSense® の機能を利用して、開発者がコード中のプロパティを参照したときに、ドロップダウン リストに許容される値を表示するようにするといいでしょう。
Enum 構造を使ってプロパティが受け付ける値を指定し、この列挙体に tsFormat などのわかりやすい名前を割り当てます。これらの値は、.NET コード エディタ (図 7) に、IntelliSense ドロップダウン リストとして表示されます。

図 7. IntelliSense が動作している様子
この列挙体は、Short や Long といった値を使用していないことに注意してください。これらは予約語であり、列挙体のメンバとして使用することはできません。その代わりに、他の開発者にもわかりやすい fLong (format long の略) のような名前を使用します。
New() コンストラクタに渡される TimeStampFormat パラメータは、モジュール レベルの mstrFormat 文字列変数を設定するために使用されます。TimeStampFormat 引数はオプションで、コンシューマ アプリケーションが形式パラメータを指定しなかった場合のために既定値が用意されています。TimeStamp プロパティの中のコードは上の例から変更されています。新しいバージョンでは、mstrFormat 変数を使って、プロパティの値として返されるタイムスタンプ文字列の形式を設定しています。
コンシューマ アプリケーションのコードも変更されています。st オブジェクト変数の宣言には、返される TimeStamp プロパティの形式の指定を含めることができます。
Dim st As New ServerTime.ServerTime( _
ServerTime.ServerTime.tsFormat.fShort)
この単純なタスクを実行する方法にはさまざまなものが考えられますが、New() コンストラクタをパラメータ付きまたはパラメータなしで使用するというテクニックは手軽で効率的です。コンポーネントを使用する開発者にとっての列挙体の利点を軽視してはなりません。
アセンブリ情報の更新
ビルドの時点で、コンパイラはコンポーネントに、実行時に非常に有用ないくつかの情報を格納します。たとえば、1 台のコンピュータには ServerTime コンポーネントの複数のバージョンがインストールされているかもしれません。コンシューマ アプリケーションは、コンポーネントのプロパティとメソッドを使い始める前に、自分がどのバージョンをロードしたのかを知る必要があります。
個々の.NET プロジェクト アセンブリには AssemblyInfo モジュールが付属しています。このモジュールは、設計時に変更することができ、コンパイルの段階でコンポーネントに組み込まれる宣言から構成されています。図 8 は、いくつかのアセンブリ属性 (AssemblyTitle、AssemblyDescription、および AssemblyCompany) を含んだ、ServerTime コンポーネントのための AssemblyInfo モジュールを示しています。

図 8. アセンブリ属性の指定
ソリューション エクスプローラで、アセンブリ コード ウィンドウを開きます。AssemblyInfo.vb という名前のモジュールをダブルクリックし、アセンブリの個々の属性の値を入力します。
AssemblyInfo.vb モジュールの末尾近くにある AssemblyVersion 属性に注意してください。この値の既定値は "1.0.*" です。アスタリスクは、DLL がコンパイルされるたびに、Visual Basic .NET にバージョン番号を自動的にインクリメントさせることを示します ("1.0.7" から "1.0.8" など)。この属性に値を入力すれば、完全なバージョン番号をハードコードすることも可能です。
コンポーネントのソース コードから DLL がコンパイルされたら、この情報は Windows エクスプローラで DLL を右クリックし、[バージョン情報] タブでアセンブリ属性を見ることによって確認できます (図 9 を参照)。

図 9. Windows エクスプローラでのアセンブリ属性の表示
名前空間の指定
.NET アプリケーションのもう 1 つの新しい便利な機能が、コンポーネント プロジェクトの中で名前空間を指定できる能力です。前に述べたように、1 つの DLL は複数のクラスを公開することができます。Visual Studio .NET は、これらのクラスを、DLL の中の名前空間としてグループ化する便利な機能を用意しています。これにより、DLL に含まれるさまざまなクラスを参照する作業が大幅に単純化されます。
名前空間を指定するには、コードの領域を Namespace および End Namespace ステートメントでマークします。たとえば、ServerTime クラスとそのプロパティのコードは、SystemInfo という名前の名前空間にラップすることができます。
Namespace ServerInfo
Public Class ServerTime
Private mdtTime As DateTime
ReadOnly Property TimeStamp() As String
Get
Try
mdtTime = Now()
Return Format(mdtTime, "Long Date")
Catch e As Exception
'例外を、処理のためにコンシューマに
'返す
Throw e
End Try
End Get
End Property
End Class
End Namespace
ServerTime クラスの TimeStamp プロパティを参照するステートメントは、次のようになります。
ServerInfo.ServerTime.TimeStamp
ServerInfo 名前空間には、ServerDiskNames や ServerDatabases などの他のクラスを含めることができます。
プロジェクトの中の複数のクラス モジュールで同じ名前空間宣言ステートメント (Namespace ServerInfo) を指定することができます。Visual Studio .NET はこれらのクラス モジュールをまとめ、コンパイル時に 1 つの DLL にします。
名前空間は、Visual Studio .NET 開発者に対し、アプリケーションの設計時に高度な柔軟性を提供します。たとえば、異なる名前空間の中に同じ名前のクラスを持つことができます。個々の名前空間には、その名前空間のためのクリーンアップ タスク (データベース ファイルのクローズ、オブジェクト変数の解放、レコード ロックの解放など) を行うクリーンアップ クラスを用意することができます。さらには、すべてのクリーンアップ クラスに、それぞれのクリーンアップ手順が異なる場合でも、同じプロパティを持たせることが可能です。
Visual Basic .NET での COM コンポーネントの使用
ここまででは、ある特定のタイプのソフトウェア コンポーネントについて説明してきました。.NET コンポーネントはつねにダイナミック リンク ライブラリ (DLL) にコンパイルされます。これは実行時に呼び出され、メモリにロードされます。
いままで説明しなかったのは、DLL はホスト アプリケーション (すなわちコンシューマ) が占有しているのと同じプロセス空間にロードされるということです。つまり、Windows はコンシューマ アプリケーションとコンポーネントを 1 つのプロセスとして管理します。コンポーネントはメモリやその他のコンピュータ リソースをコンシューマと共有します。
インプロセス コンポーネントとアウトプロセス コンポーネント
.NET のインプロセス コンポーネント アーキテクチャは、コンシューマとコンポーネントの間のきわめて高速で信頼性の高い通信を可能にします。両者は同じプロセス空間を共有しているので、Windows はコンシューマとコンポーネントの間でメッセージを受け渡す必要がありません。コンシューマは、コンポーネントのプロパティをきわめて高速に読み書きすることができます。
しかし、すべてのサービス プロバイダがインプロセス コンポーネントとして動作するわけではありません。これまでに、コンポーネント オブジェクト モデル (COM) アーキテクチャに準拠するレガシー アプリケーションが何千種類も作成されてきました。これらのサービス プロバイダは、(Microsoft の ActiveX 仕様に基づく) まったく別のメカニズムを使ってクライアント アプリケーションと通信を行います。COM ベースの ActiveX サーバーは、自分のインターフェイスを、.NET アプリケーションのマニフェストにほぼ相当するタイプ ライブラリとして公開します。タイプ ライブラリは COM サーバーが公開しているクラスの定義を含んでいます。これには、個々の公開されたクラスがサポートしているプロパティ、メソッド、およびイベントが含まれます。
COM コンポーネントの.NET との統合
Microsoft ActiveX® コンポーネントの.NET アプリケーションとの統合は、.NET コンポーネントのアプリケーションへの組み込みによく似ています。まず最初に、COM コンポーネントのタイプ ライブラリが.NET アプリケーションの参照に追加されます。次に、COM コンポーネントが公開しているクラスからオブジェクトが作成され、インスタンス作成されます。その後、Visual Basic .NET コードが COM オブジェクトのプロパティ、メソッド、およびイベントを操作します。
COM コンポーネントは、.NET アプリケーションのプロセス空間の外の、独自のプロセス スレッドの中で実行されます。つまり、Windows は COM コンポーネントのリソース要件を独立に管理し、コンポーネントとコンシューマの間でメッセージを受け渡します。COM のアウトプロセス統合アーキテクチャは.NET のインプロセス デザインと比べるといくぶん遅くなりますが、ほとんどのユーザーはその違いに気づかないでしょう。
Microsoft Word を COM ベースの ActiveX コンポーネントとして組み込む.NET Windows アプリケーションを作成するには、次の操作を行います (この例を実行するためには、Microsoft Word がコンピュータにインストールされている必要があります)。
- Visual Studio .NET を開きます。[ファイル] メニューの [新規作成] をクリックし、[プロジェクト] をクリックします。
- [新しいプロジェクト] ダイアログ ボックスの [プロジェクトの種類] で、[Visual Basic プロジェクト] を選択します。[テンプレート] では [Windows アプリケーション] を選択します。新しい Windows アプリケーション プロジェクトに COMComponentIntegration という名前を付け、[OK] をクリックします。
- ソリューション エクスプローラで、[参照設定] を右クリックし、コンテキスト メニューの [参照の追加] をクリックします。
- [参照の追加] ダイアログ ボックスで、[COM] タブをクリックし、コンポーネントのリストで [Microsoft Word] を探します (このデモンストレーションでは、Word の具体的なバージョンはあまり重要ではありません)。
- [Microsoft Word] を強調表示し、[選択] をクリックして [選択されたコンポーネント] のリストに追加し、[OK] をクリックします。
- .NET は、Word オブジェクト ライブラリのラッパー (後述) を生成するかどうかを尋ねます。ここでは [はい] をクリックして、.NET にラッパーを生成させます。
相互運用アセンブリについて
COM タイプ ライブラリと.NET アセンブリは、内部的にはまったく違うものなので、.NET アプリケーションは COM コンポーネントのライブラリが提供する情報を直接に使用することはできません。.NET は、COM タイプ ライブラリを囲むラッパーか、タイプ ライブラリに含まれている情報から作成されたプライマリ相互運用アセンブリを使用して、.NET アプリケーションと COM コンポーネントの間のインターフェイスを提供します。
プライマリ相互運用アセンブリは、COM コンポーネントのベンダが提供している DLL で、コンポーネントを.NET アプリケーションと統合するときのためのものです。相互運用アセンブリがない場合、.NET はコンポーネントのタイプ ライブラリが公開している個々のクラスへの参照を含んだ DLL を作成します。この DLL は、.NET が COM コンポーネントのタイプ ライブラリに発見したクラス インターフェイスをインポートすることによって作成されます。
COM タイプ ライブラリ ラッパーは、Visual Basic .NET プロジェクトに新しい参照として追加されます。ソリューション エクスプローラでラッパー DLL を右クリックし、コンテキスト メニューから [プロパティ] を選択すると、いくつかの興味深いプロパティ値が表示されます。これらのプロパティの中には、ラッパー DLL へのパスがあります。.NET は DLL を、コンシューマ アプリケーションのアセンブリに含まれている他のコンポーネント ライブラリと同じ obj ディレクトリに格納していることがわかります。
obj フォルダには、コンポーネントのラッパー DLL に加えて、他のラッパー DLL も格納されていることがあります。これらの DLL は、COM コンポーネントが使用するセカンダリ タイプ ライブラリへのインターフェイスを提供しています。Microsoft Word の例では、Word 用に作成された DLL に加えて、Microsoft Office と VBIDE の相互運用 DLL が存在するはずです。
Visual Basic .NET からの COM オブジェクトのプログラミング
COM コンポーネントを統合するために必要なコードは、.NET の組み込みコンポーネントを使用するためのコードによく似ています。次のプロシージャ (btnCreateWordDocument という名前のボタンの背後の Click イベント ハンドラ) は、Word タイプ ライブラリが公開している Application クラスのオブジェクトを作成します。その後、既定の Word ドキュメント テンプレート (Normal.dot) から新しいドキュメントを作成し、ドキュメントに 1 行のテキストを追加し、ドキュメントを保存します。
Private Sub btnCreateWordDocument_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnCreateWordDocument.Click
Dim objWord As Word.Application
Dim strPath As String
objWord = New Word.Application()
With objWord
.Visible = True
.Documents.Add( _
Template:="Normal.dot", _
NewTemplate:=False)
.Selection.TypeText( _
Text:="this is a test")
.ActiveDocument.SaveAs( _
FileName:="Test.doc")
.Documents.Close( _
SaveChanges:=Word.WdSaveOptions.wdDoNotSaveChanges)
.Quit()
End With
objWord = Nothing
End Sub
このコード例の末尾近くで、Close メソッドの SaveChanges 引数として与えている値に注目してください。この値は、Word 相互運用 DLL に格納されている組み込み定数 (wdDoNotSaveChanges) を参照しています。Word 相互運用 DLL には、.NET プロジェクトからアクセス可能な多数のプロパティ、メソッド、イベント、および定数値が含まれています。
.NET アプリケーションからの COM オブジェクトの管理
.NET インプロセス コンポーネントと COM ベースの ActiveX コンポーネントの大きな違いの 1 つとして、COM オブジェクトの有効期限は、Visual Basic .NET コードから明示的に制御する必要があります。上のリストの末尾近くに、objWord を Nothing に設定するコードがあることに注意してください。.NET で作成されたコンポーネントを扱うときには、コンポーネントは.NET のガーベジ コレクタによって廃棄されます。.NET コンポーネントはマネージ コードから構成されているので、.NET は、オブジェクトへの最後の参照がスコープから外れた時点で、オブジェクトが占有しているメモリを破棄します。
COM オブジェクトの場合は、そうは行きません。いったん COM オブジェクトがインスタンス作成されると、Windows は通常、オブジェクトへの参照 (上のリストでは objWord) が Nothing に設定されて明示的に破棄されるまで、オブジェクトをメモリ内に残します。Word のような大きな COM コンポーネントを扱う場合、アプリケーションの終了時にオブジェクトを明示的に破棄するのを忘れると、大変なメモリ リークが生じます。
COM オブジェクトと.NET コンポーネントの他の違いについては、DLL ラッパーがそのほとんどを処理してくれます。このような違いは、たとえば Windows がコンポーネント (.NET または COM) をメモリ内で移動するときに生じます。これは、Windows が、アプリケーションによって使用されるメモリを最適化しようと試みるために発生します。.NET アプリケーションは自分のコンポーネントの位置を問題なく追跡できます。コンポーネントとそのデータは共通言語ランタイムによって管理されているからです。一方、COM オブジェクトはアンマネージ コードを含んでいるので、.NET アプリケーションはオブジェクトが移動されたときに COM オブジェクトの参照を追跡することはできません。
.NET が作成する COM オブジェクトのランタイム ラッパーは、COM オブジェクトの移動時に更新されるメモリ参照を追跡してくれます。ラッパーが静的なメモリ参照を更新された位置に自動的に変換してくれるので、コンシューマ アプリケーションから見るとアドレスに変化はありません。
COM オブジェクトを含んでいる.NET アプリケーションの配布
COM オブジェクトを含んでいる.NET アプリケーションの配布は、ほとんどの点で純粋な.NET アプリケーションの配布と同じです。唯一の違いは、エンド ユーザーのコンピュータにインストールされている共通言語ランタイムが COM コンポーネントのインターフェイスを理解できるように、.NET によって作成された相互運用 DLL を含めなくてはならないということです。
また、COM オブジェクトはユーザーのコンピュータ上に正しくインストールされ、登録されていなくてはなりません。COM のインストールを成功させるための一般化された規則を示すのは困難です。ほとんどの COM サーバー (Microsoft Word など) は、適切なフォルダ ツリーとレジストリ キーを作成する独自のインストール プログラムを持っています。一般論として、COM サーバーがユーザーのコンピュータ上で正常に動作するのであれば、.NET アプリケーションのコンテキスト内でも正常に動作するはずです。
Visual Basic 6.0 との違い
Visual Basic 6.0 と Visual Basic .NET におけるコンポーネントの作成にはさまざまな違いがあります。ほとんどの違いは、複雑なアプリケーションの作成、コンポーネントのテストと配置、およびアプリケーション間でのコンポーネントの共有を簡単にすることで、開発エクスペリエンスを強化する役割を果たしています。
- .NET プロジェクトは、プロジェクトのファイルの整理を簡単にする機能を多数備えています。Visual Basic 6.0 では個々のクラスが 1 つの.CLS ファイルを構成していたのに対し、Visual Basic .NET コード モジュールは複数のクラスを含むことができます。.NET のアプローチでは、1 つのコード モジュール内でクラスを論理的にグループ化し、クラス間の関係をより簡単に認識できるようにすることができます (データ アクセス、ファイナンス、ディスクとファイルの管理など)。
- .NET コンポーネントはユーザーのコンピュータ上に登録されるわけではありません。Visual Basic ActiveX コンポーネントは、各ユーザーのコンピュータにインストールし、登録しなくてはなりません。個々の.NET コンポーネントは、コンシューマ アプリケーションがそのコンポーネントを使用するために必要とするすべてのインターフェイス情報を含んでいます。コンポーネントのインターフェイス (クラス、プロパティ、メソッド、およびイベント) は、.NET オブジェクト ブラウザと IntelliSense を通してドキュメント化されています。
- .NET のエラー処理は、Visual Basic 6.0 の "On Error GoTo" モデルと比べると大幅に改善されています。.NET のエラー処理構文は簡単に認識することができ、.NET コンポーネントは必要ならば Exception オブジェクト全体を返すことができます。
- クラス コンストラクタはパラメータを受け付けます。これにより、インスタンス作成が完了するのを待ってからプロパティの初期値を設定するという方法の代わりに、オブジェクトがインスタンス作成される時点で起動情報を指定することができます。
- .NET クラスは、名前空間を使って論理的に整理することができます。名前空間は、別の名前空間の中のクラスと同じ名前を持つクラスを含むことができます。1 つの DLL は複数の名前空間を含むことができます。Visual Basic 6.0 は名前空間をサポートしていません。
要約
このドキュメントでは、単純な.NET コンポーネントを設計し、DLL として実装するプロセスについて説明しています。個々の.NET DLL は、それぞれ多数のプロパティ、メソッド、およびイベントを公開する複数のクラスを含むことができます。このドキュメントでは、単純ながらも有用なタスクを実行するクラス モジュールを開発する方法、そのクラス モジュールをベースにしたコンポーネント プロジェクトを設定する方法、さらにそのコンポーネントを.NET Windows フォーム プロジェクトに組み込む方法について説明しました。
Visual Studio .NET と Visual Basic 6.0 では、クラスとコンポーネントの作成方法に大きな違いがあります。プロパティの公開は、Visual Basic 6.0 とはまったく異なる操作となっています。Visual Studio .NET のエラー処理は、高度に構造化されており、しかも柔軟性を備えています。Visual Studio コンポーネントはユーザーのコンピュータ上に登録する必要がありませんが、コンシューマ アセンブリは、正常に動作するためには、コンポーネント DLL への参照を持つ必要があります。
執筆者について
Michael Groh は、Ocala, Florida の PC Productivity Solutions の社長で、Visual Basic と.NET 関連のトピックを専門とするコンサルタント、ライター、トレーナーです。Access/Visual Basic/SQL Advisor のテクニカル エディターでもあり、20 冊以上のコンピュータ関連書籍に寄稿し、150 本以上の雑誌記事を執筆しています。Michael Groh は全米のデータベース カンファレンスで頻繁に講演を行っています。New Riders Publishing の Windows、データベース、およびオペレーティング システム関連の書籍のプロダクト ディレクターを務めた経験があります。
Informant Communications Group について
Informant Communications Group, Inc. (www.informant.com) は、情報テクノロジ セクタに焦点を当てた多角的なメディア会社です。1990 年に創設された ICG は、ソフトウェア開発関連の出版事業、カンファレンス、カタログの発行、および Web サイトを専門としています。米国と英国にオフィスを持つ ICG は、有名なメディアおよびマーケティング コンテンツ インテグレータとして、IT プロフェッショナルに対して高品質の技術情報を提供してきました。
Copyright© 2002 Informant Communications Group and Microsoft Corporation
テクニカル エディティング: PDSA, Inc.または KNG Consulting
|