Object指向再入門

Visual Basicプログラマのための
オブジェクト指向プログラミング入門

.NETの前に押さえておきたいVisual Basic的オブジェクト指向について



初音 玲 HATSUNE, Akira



マイクロソフトの.NET戦略やその開発ツールであるVisual Studio.NETの姿も徐々に見えてきた。.NETの思想自体も興味深いが、Visual Basicのプログラマなら、やはり新Visual Basicが気になるだろう。Visual Basicのバージョンの法則として、バージョン3.0でOLEの採用、バージョン5.0でネイティブコンパイルの搭載など、奇数バージョンで大々的な仕様拡張が行なわれるという傾向もあり、気になるところだ。来るべきVisual Basic.NETでは、本格的なオブジェクト指向言語になるそうだし、今までの開発スタイルが通用するのか、期待と不安はつきない。そこで今回は、そもそもオブジェクト指向言語とはどういったものなのか、また、現在のVisual Basicは、どうして“本格的な”オブジェクト指向言語と評されないかについて探ってゆきたいと思う。

まずは設計ありき

 どのようなプログラミング言語でもきちんとした設計なくしては、効率的で保守性の高いコードを記述することはできない。オブジェクト指向言語もしかりである。オブジェクト指向言語を活用するためには、それにあった設計、つまりオブジェクト指向設計(Object Oriented Design)が必要になってくる。
 しかし、その前に抑えておきたい考え方がある。それは、構造化プログラミングだ。

構造化プログラミングの考え方

 構造化プログラミングとは、Goto文の乱用により可読性が著しく低下したプログラムの発生を抑える目的で、1970年代にダイクストラ(Dijkstra)氏により提唱された「プログラム全体を理解しやすくする」という考え方だ。その特徴としては、
などがある。
 構造化プログラミングというものを知らずにGoto文を使っている人にとっては、なぜGoto文を廃止しなければならないのか理解に苦しむだろう。「Goto文を使ったほうが効率的だ」「Goto文を使ったほうがプログラムが読みやすい」という声も聞こえてくる。しかし、結果的に廃止するということになっているが構造化プログラミングのコンセプトは、Goto文という考え方が不要だとしている訳ではない。
 事実、if〜elseif〜else〜endifという構造化if文がなければ、Goto文なしで「選択処理」を記述できない(リスト1)し、「反復処理」にしても、For文やWhile文がなければGoto文なしで記述できない(リスト2)。構造化用の命令がない言語では、当然Goto文を使わざるを得ないのだ。では、そういったものは構造化プログラミングと呼べないかと言えば、答えは“否”なのである。もちろん、言語仕様として構造化用の命令があるに越したことはないのだが、たとえGoto文を使っていたとしても、アルゴリズムの3要素を実現していれば、構造化という観点からすれば十分正しいプログラムなのだ。
 では、どんなGoto文の使い方がいけないのだろうか。たとえば、Goto文で実行が移したときに、最終的にどこに戻ってくるのかわからないような使い方だ。もちろん、最初からそのような構造になっているのは、よほどの素人が作成したプログラムくらいだろう。しかし、作成当時はGoto文を配置した意味も覚えているし、飛び先も単純かもしれないが、メインテナンスや仕様変更を繰り返した結果、Goto文であちこちに飛び回るスパゲティコードの状態にたどり着くことになるのも事実だ。そのコードが有用であればあるほど、他の言語に移植したり長年使われたりするのだから、後々のメインテナンスを考えるとやはりGoto文は避けたほうがよいだろう。

リスト1:構造化If文がないとき
    If Not 条件式1 Goto <ラベル1>
    実行文1
    Goto <ラベル>
<ラベル1>
    If Not 条件式2 Goto <ラベル2>
    実行文2
    Goto <ラベル>
<ラベル2>
       :
<ラベル>
    実行文
       :

リスト2:反復命令がないとき
<ラベル>
    If Not 条件文1 Goto <ラベル1>
    実行文1
    実行文2
       :
    実行文n
    Goto <ラベル>
<ラベル1>
    実行文
       :

On Error Goto文とGoto文の違い

 たとえば、「Goto文を使わない」とコーディング規約に定めて、構造化プログラミングを念頭においた開発を心掛けたしよう。このとき、Visual Basicを開発言語に選択すると、使ってよいものか判断に困る命令が存在してしまう。それは、On Error Goto文だ、Gotoという名称からすれば、Goto文の一種であるので、使うと構造化プログラミングから逸脱しやすいコードになってしまうかもしれないとの疑問が沸くだろう。しかし、On Error Goto文はGotoという名称を使っているが、リスト3のようにプロシージャの最後に飛ぶ先を記述し、正常ルートでは実行されないように工夫する必要もあるが、Resume Next文などにより、戻り先を明確化できるので、単純なGoto文とは別物だといえる。

リスト3:On Error Gotoの正しい使い方の一例
Private Sub subPrint()
  On Error Goto errPrint:

  実行文1
  実行文2
     :
  実行文n

exitPrint:
  On Error Resume Next
  Exit Sub

errPrint:
  MsgBox Error$
  Resume exitPrint:
End Sub

オブジェクト指向設計の考え方

 オブジェクト指向設計(Object Oriented Design)の考え方は、難しいようでいて、そのコンセプトは単純明快だ。OODにおいてまず設計していくのは、「やりたいこと」を実現してくれるモノ(オブジェクト)の定義だ。
 これは何も目新しい考え方ではない。たとえば今までも、まず必要なデータを設計してから全体にアプローチするDOA(Data Oriented Approach)や、まず必要な処理を設計してから全体にアプローチするPOA(Process Oriented Approach)という考え方もあるからだ。しかし、DOAやPOAでは、設計するオブジェクトの種類が限られているために、どうしても次に設計すべき要素から影響を受けてしまうことがある。OODでまず設計するオブジェクトとは、このことを考慮して、データでも処理でもよいことになっている。つまり、とにかく「“やりたいこと”を実現してくれる」オブジェクトをどんどん設計していってしまおうということなのだ。

オブジェクト指向と非オブジェクト指向

 オブジェクト指向とは、現実をモデル化することだと言われている。それは、現実の世界の振る舞いが、オブジェクト指向に基づいているからに他ならない。
 身近な例としては「ビデオを再生してテレビで見る」などがわかりやすい。もし、オブジェクト指向ではないと(現実的には考え難いのだが)テレビとビデオの設計図を購入し、部品をかき集めて作り上げることになるだろう。オブジェクト指向であれば、テレビとビデオを購入し、2つをビデオケーブルで結びつければ目的を果たすことができる。さらに、ビデオケーブルを繋ぐことがわからなかったり、ケーブルが数多く必要だったりした場合、ビデオ内臓テレビという選択肢もあるだろう。
 多かれ少なかれ、コンピュータシステムは、現実世界の問題を解決するために存在するので、現実世界をモデル化しやすい考え方が導入できれば、モデル化するときに表現できないことも少なくなるだろう。だからこそ、オブジェクト指向なのである。
 しかし、同時にOODの難しさもそこにある。たとえば先の例で言えば、テレビとビデオの2つのオブジェクトが必要なのか、ビデオ内蔵テレビのオブジェクトが必要なのか判断することなどだ。ビデオ内蔵テレビの場合、確かに取り扱いが楽だったり2つのオブジェクトを連携するよりも性能がよかったりするかもしれないが、新しいビデオ規格に対応しようとしたら影響がないテレビも含めて買い換える必要が出てきてしまう。どこまでが普遍的なものなのか、どこからが個別のものなのかを判断するのが、OODでの肝と言えるだろう。もちろん、現実世界と異なり、オブジェクトの利用者は新たなオブジェクトを定義できるので、テレビオブジェクトとビデオオブジェクトを購入してきて、それらを使うビデオ内蔵オブジェクトを新たに定義することもできる。こういったこともオブジェクト指向の特徴だ。

オブジェクト指向の特徴

クラスとインスタンス

“オブジェクトを設計する”とは、“クラスを定義する”と言い換えることができる。では、オブジェクト=クラスかと言えば、必ずしもそうではない。
 たとえば、“Visual Basic Magazine 2001年3月号”というオブジェクトを設計するときには、“雑誌”クラスを定義し、そこにタイトルや号数などの値を与えて実体化して“Visual Basic Magazine 2001年3月号”インスタンスして、はじめて目的のものを手に入れられる(図1)。ここらあたりが、オブジェクト指向の最初のハードルだろう。
 では、なぜクラスとインスタンスという2段階の考え方を導入しているのだろうか。それは、“Visual Basic Magazine 2001年3月号”オブジェクトを定義せずに、“雑誌”クラスを定義することで、他の雑誌や他の号数のオブジェクトに使いまわせるからだ。

図1:クラスとインスタンス
図1

カプセル化

 オブジェクト指向設計では、データと処理の区別をなくして設計してゆく。それは、データとそれを取り扱う方法を分離せず、必ずペアで考えることも意味している。つまり、あるデータが存在した場合、そのデータに対する読み書きや演算は、そのデータを含んだオブジェクトの仕様としてのみ存在することになる。もちろん、これも目新しい考え方ではない。Visual Basicでも変数のスコープという考え方があり、スコープ外からは変数の値が参照できないなどは、カプセル化の一例と言えるだろう。このようにカプセル化は、オブジェクト指向に特有の考え方ではなく、コードの独立性を高めるために今までも行なわれてきた手法だ。オブジェクト指向では、オブジェクトという考え方を導入することでいろいろな局面に対応できるようになっている。

メッセージ

 カプセル化したデータに対する読み書き演算は、オブジェクトの仕様としてのみ存在する。オブジェクト指向では、この仕様のことをメッセージと名付けている(図2)。インターフェイスをメッセージのみに限定することで、内部的な処理やデータを外部に知られずに使わせることができるようになる。よく“内部処理やデータを知らなくても使うことができる”と表現されるが、そういったニュアンスよりも知られないようにするというニュアンスの方が近い気がする。
 もちろん、これも目新しい仕組みではない。たとえば、プロシージャ内のローカル変数の値を使いたいときは、プロシージャのパラメータとして、ローカル変数を返却する仕様とすればよい(リスト4)。

図2:メッセージ
図2

リスト4: カプセル化の一例(frmCapsuleより抜粋)
Option Explicit
Private Sub cmdGet_Click()
  ' これ以外にローカル変数にアクセスする方法はない
  lblResult = strLocalGet()
End Sub
Private Function strLocalGet() As String
  Static lngCount As Long

  lngCount = lngCount + 1
  strLocalGet = lngCount     ' ローカル変数を返却
End Function

メソッドとプロパティ

 オブジェクトに対してどのようなメッセージが有効かを規定する方法が、メソッドとプロパティだ(図3)。この両者は基本的に似ているが、メソッドは演算などのいろいろな動作を依頼するメッセージであり、プロパティはオブジェクトが管理しているデータを読み書きするメッセージという区別があるが、基本的にはクラス内の処理やデータに対する唯一のアクセス方法、つまり、インターフェイスであるのに変わりない。

図3:メソッド
図3

クラスの継承と派生

 継承(インヘリタンス)とは、あるクラス(基本クラス)の機能を引き継ぐ別のクラス(派生クラス)を作成する機能だ。上位モジュールと下位モジュールの関係に似ているが、継承では派生クラス側には、基本クラスからの変更点や拡張点のみを記載すればよく、基本クラスの機能そのままでよいときには、何も記述する必要がないのが大きく異なる(図4)。

図4:継承と派生
図4

 継承を使えば、基本クラスを書き換えずに基本クラスの拡張が可能になる点が大きなメリットだ。とくに基本クラスのメソッドやプロパティを派生クラスで同じメソッド名やプロパティ名で書き換え(オーバーライド)可能な点も便利だろう(図5)。

図5:オーバーライド
図5

多態性(ポリモフィズム)

 ひとつの基本クラスから複数の派生クラスを作成し、派生クラス独特の動作をするようにメソッドをオーバーライドした上で、同じメッセージをそれぞれの派生クラスに送ると、それぞれの派生クラス特有の動作をする。このようなことを多態性と呼ぶ。多態性は、Windowsを使っていると日常的に遭遇している。たとえば、右クリックしたときの動作や表示されるメニューがソフトウェアごとに別々であるというようなことだ。

Visual Basicにおけるオブジェクト指向

 オブジェクト指向の考え方を調べてみれば、今までも工夫してきた点を定型的な手法や言語仕様に昇華してきたことがわかるだろう。さらにVisual Basicでもお馴染みの用語がいろいろ出てきたので「Visual Basic 6.0でもオブジェクト指向のプログラミングができるのではないか、だとしたらVisual Basic.NETではオブジェクト指向言語として大々的な改変が行なわれるという話と矛盾するのではないか」と思われるかもしれない。
 結論から言えば、Visual Basic 6.0以前は、オブジェクト指向言語ではなくオブジェクト指向っぽい言語でしかない。では、どういった点が言語的に機能不足なのだろうか。オブジェクト指向に照らし合わせて、Visual Basicでプログラミングしてみれば、その点が明確になってくる。

クラスモジュール再考

 Visual Basicのオブジェクト指向っぽい点、オブジェクト指向言語であると錯覚される点が、クラスモジュールの存在だろう。このクラスモジュールは、もちろんオブジェクト指向のクラスから考えられたものだ。
 たとえば、clsClsという名前を付けたクラスモジュールを作成したとしよう。オブジェクト指向のクラスと同様に、このクラスモジュールを使うためには、実体化してインスタンスとしなければならない。そのためには、

Set objCls = New クラスモジュール名
のようにクラスモジュールを実体化する命令を実行する必要がある。もし、実体化せずにクラスモジュールを直接指定してもなにもできない(図6)。ここまでであれば、十分オブジェクト指向言語と言えるだろう。
 もちろん、このクラスモジュールをActiveX DLLやActiveX EXEとしてコンパイルして、他のVisual Basicプロジェクトから使うこともできる。

図6:インスタシング
図6

クラスモジュールのインターフェイス

 クラスモジュールのインターフェイスとしては、当然のようにメソッドとプロパティがある。プロパティには、LetとGetの定義があり、それぞれ値の設定、値の取得に機能が限定されている。ただし、LetとGetの定義に同じプロパティ名を設定できるので、読み書き可能なプロパティを定義することも可能だ。メソッドについては、プロパティと異なり、特別にメソッドの定義というものはなく、プロシージャや関数として記述する(リスト5)。

リスト5:クラスモジュール(clsClsより抜粋)
Option Explicit
Private intNum  As Integer
Private Property Get prpValue() As Integer
' クラス内プロパティ
  prpValue = intNum
End Property
Private Property Let prpValue(ByVal vintValue As Integer)
' クラス内プロパティ
  intNum = vintValue
End Property
Friend Property Get fprpValue() As Integer
' プロジェクト内プロパティ
  fprpValue = intNum
End Property
Friend Property Let fprpValue(ByVal vintValue As Integer)
' プロジェクト内プロパティ
  intNum = vintValue
End Property
Public Property Get pprpValue() As Integer
' 公開プロパティ
  pprpValue = intNum
End Property
Public Property Let pprpValue(ByVal vintValue As Integer)
' 公開プロパティ
  intNum = vintValue
End Property
Private Function intValueGet() As Integer
' クラス内メソッド
End Function
Private Sub subValueGet()
' 公開メソッド
  intNum = intNum + 1
End Sub
Private Sub subValueSet(ByVal vintValue As Integer)
' クラス内メソッド
  intNum = vintValue
End Sub
Friend Function fintValueGet() As Integer
' プロジェクト内メソッド
  fintValueGet = intNum
End Function
Friend Sub fsubValueGet()
' 公開メソッド
  intNum = intNum + 1
End Sub
Friend Sub fsubValueSet(ByVal vintValue As Integer)
' プロジェクト内メソッド
  intNum = vintValue
End Sub
Public Function pintValueGet() As Integer
' 公開メソッド
  pintValueGet = intNum
End Function
Public Sub psubValueGet()
' 公開メソッド
  intNum = intNum + 1
End Sub
Public Sub psubValueSet(ByVal vintValue As Integer)
' 公開メソッド
  intNum = vintValue
End Sub

 もちろん、メソッドやプロパティにも、そのスコープを定義するPrivate、Friend、Publicという区別があり、図6で表示されているヒントを見てもわかるように、同じVisual Basicプロジェクト内でもPrivateなインターフェイスにアクセスすることはできず、FriendやPublicなインターフェイスにのみアクセスできる。また、ActiveX DLLやActiveX EXEとしたときには、Friendにもアクセスできなくなり、Publicなインターフェイスにしかアクセスできなくなる。
 なお、ひとつのクラスモジュールから複数のインスタンスも作成可能なので、このように作成したクラスモジュールを複数のインスタンスとして実体化したときは、そのインスタンス間では別々の変数領域が確保される(リスト6、図7)。

図7:同一クラスからの複数インスタンス
図7

リスト6:クラスモジュールを使う(frmClsより抜粋)
Option Explicit
Private aobjCls(1 To 2) As clsCls
Private Sub cmdPropSet_Click(index As Integer)
  aobjCls(index).fprpValue = aobjCls(index).fprpValue + 1
  lblFint(1).Caption = aobjCls(1).fintValueGet
  lblFprp(1).Caption = aobjCls(1).fprpValue
  lblPint(1).Caption = aobjCls(1).pintValueGet
  lblPprp(1).Caption = aobjCls(1).pprpValue
  lblFint(2).Caption = aobjCls(2).fintValueGet
  lblFprp(2).Caption = aobjCls(2).fprpValue
  lblPint(2).Caption = aobjCls(2).pintValueGet
  lblPprp(2).Caption = aobjCls(2).pprpValue
End Sub
Private Sub Form_Load()
  Set aobjCls(1) = New clsCls
  Set aobjCls(2) = New clsCls
End Sub

Private Sub Form_QueryUnload( _
 Cancel As Integer, UnloadMode As Integer)
  Set aobjCls(1) = Nothing
  Set aobjCls(2) = Nothing
End Sub

メソッドにするかプロパティにするか

 クラスモジュールを作成したときに悩む問題のひとつが、プロパティとするのかメソッドにするのかという点だろう。
 Visual Basicの言語仕様的にも、プロパティとメソッドの機能的な違いは、ほとんど存在しないことも悩みを増幅する一因だ。そこで、値の変更などはメソッドの役目と考えよう。たとえば、リスト6の“値の加算”などは、

aobjCls(index).psubValueGet
のようにメソッドとして実装するものだが、プロパティの定義の中で値の演算を行ない、演算後の値を返却するような作りとすることももちろん可能だ。しかし、誰にも誤解されないようなインターフェイスとするためには、プロパティの定義の中で変数値を変更するなどは行なわないほうがよいだろう。

コレクションというもの

 コレクションはクラスの配列のようなものだ。コレクションとすることで、直接複数のインスタンスを制御するよりも使いやすい形にできる。注意点としては、コレクション自体もインスタンスとして実体化して使うクラスなので、コレクション化しているクラスのPublicなインターフェイスのみが使えるという点だ。インターフェイスのヒントが表示されないしコンパイル時にエラーにもならない(リスト7)ので注意してほしい。もちろん、実行時にはエラーとなり、Publicなインターフェイスのみアクセス可能だ(図8)。

図8:コレクションオブジェクトを使う
図7

リスト7:Collectionオブジェクトを使う(frmCollectより抜粋)
Option Explicit
Private colClses  As New Collection
Private Sub cmdPropSet_Click(index As Integer)
  colClses.Item(index).psubValueGet
  On Error Resume Next
  lblFint(1).Caption = colClses.Item(1).fintValueGet
  lblFprp(1).Caption = colClses.Item(1).fprpValue
  lblPint(1).Caption = colClses.Item(1).pintValueGet
  lblPprp(1).Caption = colClses.Item(1).pprpValue
  lblFint(2).Caption = colClses.Item(2).fintValueGet
  lblFprp(2).Caption = colClses.Item(2).fprpValue
  lblPint(2).Caption = colClses.Item(2).pintValueGet
  lblPprp(2).Caption = colClses.Item(2).pprpValue
End Sub
Private Sub Form_Load()
  Dim aobjCls(1 To 2) As clsCls
  
  Set aobjCls(1) = New clsCls
  Set aobjCls(2) = New clsCls
  
  colClses.Add aobjCls(1)
  colClses.Add aobjCls(2)
  
  Set aobjCls(1) = Nothing
  Set aobjCls(2) = Nothing
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, _
                             UnloadMode As Integer)
  Dim objCls  As clsCls
    
  For Each objCls In colClses
    colClses.Remove 1
  Next
End Sub

インプリメント

 クラスモジュールに対してインプリメントを行なうことができる。この機能は、インターフェイスのひな型となるクラスモジュールを用意し、そのひな型クラスモジュールに対して、他のクラスモジュールからインプリメントすることで、ひな型インターフェイスを自動的に公開できるというものだ。もちろん、公開できるひな型インターフェイスは、Publicなインターフェイスのみだ(図9)。このインプリメントという機能は、複数のクラスモジュールからインプリメントできることを利用して、クラスの多態性を実現しやくする仕組みとも言えるだろう。

図9:インプリメントを使う
図9

 なお、ひな型クラスモジュールが、基本モジュールのようになり、それを使うクラスモジュールが派生モジュールのように見えるが、ひな型クラスモジュールのロジックはまったく影響を与えられない。たとえば、リスト8のようにひな型クラスモジュールのインターフェイスのみを記述したとしよう。もし、継承がサポートされているならば、これだけでひな型クラスモジュールと同じ動作するはずだ。しかし、まったく何も起こらないクラスモジュールとなってしまう(図10の上段の結果)。

図10:インプリメントを使う
図10

リスト8: インターフェイスのみ(clsImpleより抜粋)
Option Explicit
Implements clsCls

Private Function clsCls_pintValueGet() As Integer
End Function

Private Property Let clsCls_pprpValue(ByVal RHS As Integer)
End Property

Private Property Get clsCls_pprpValue() As Integer
End Property

Private Sub clsCls_psubValueGet()
End Sub

Private Sub clsCls_psubValueSet(ByVal vintValue As Integer)
End Sub

クラスの継承はどうするのか

 クラスモジュールを継承する機能はVisual Basicにはない。ここがVisual Basicがオブジェクト指向言語ではなく、オブジェクト指向っぽい言語だと評価される点だ。では、どうにもならないかと言えば、インプリメントとひな型クラスモジュールのインスタンシングを併用するとそれっぽいことが可能になる。
 まず、ひな型クラスモジュールをインプリメントしてインターフェイスを公開する。次にインプリメント側クラスモジュールのInitialize時にひな型クラスモジュールをインスタンシングして、公開しているインターフェイスの中でインスタンスしたインターフェイスを呼び出すという手順を取る(リスト9)。もちろん、単純に呼び出さずに独自のコードを追加して、オーバーライドを実現することもできる。
 しかし、どうみてもエレガントではないし、ある程度のコード量も必要なので、Visual Basicには、オブジェクト指向言語としての継承は存在しないという評価を覆すまでにはいたらない。Visual Basic.NETでは、このあたりが拡張されてくる。

リスト9: 継承もどきの実現(clsImple2より抜粋)
Option Explicit
Implements clsCls
Private objCls  As clsCls
Private Sub Class_Initialize()
  Set objCls = New clsCls
End Sub
Private Sub Class_Terminate()
  Set objCls = Nothing
End Sub
Private Function clsCls_pintValueGet() As Integer
' 公開メソッド
  clsCls_pintValueGet = objCls.pintValueGet
End Function
Private Property Let clsCls_pprpValue(ByVal RHS As Integer)
' 公開プロパティ
  objCls.pprpValue = RHS
End Property
Private Property Get clsCls_pprpValue() As Integer
' 公開プロパティ
  clsCls_pprpValue = objCls.pprpValue
End Property
Private Sub clsCls_psubValueGet()
' 公開メソッド
  objCls.psubValueGet
  objCls.psubValueGet     ' 増分値を2倍に拡張
End Sub
Private Sub clsCls_psubValueSet(ByVal vintValue As Integer)
' 公開メソッド
  objCls.psubValueSet (vintValue)
End Sub

Visual Basic.NETの可能性と互換性

 Visual Basic 6.0とVisual Basic.NETには100%の互換性がないのは明らかになっている。それは、本格的なオブジェクト指向言語として脱皮するためには仕方がないことなのだろうか。どう考えても、その点のみに注目していては、互換性がない理由は見えてこない。CLR(Common Language Runtime)で動作しつつ、互換性を確保することも可能だという思いも捨てきれない。
 まったくの推測だが、.NET言語では共通のCLR上で動作するので、このあたりが影響していると思われる。また、マイクロソフトの過去の例からすれば、互換性に囚われずに作られた製品にこそ画期的なものが多いので、互換性が低いことは確かにマイナス評価ではあるが、Visual Basic.NETが画期的な製品として発売される期待値は十分に高いだろう。
 でも、せっかくVB5.0で搭載されたネイティブコンパイル機能がVisual Basic.NETにないのは寂しい限りだ。DelphiやVC++のようにスタティックリンク機能まで欲しいくらいなのだからネイティブコンパイル機能も是非復活して欲しい。


VB Magazine ライブラリ| Visual Basic WorkGroup
int21 ホームページ| PCDN ホームページ

PCDN
Copyright (c) 1998 int21 CorporationAll Rights Reserved.
For questions or comments, please send mail to: pcdn@int21.co.jp