Visual Basic テクニック |
インターネットで検索したらサンプルがC#でがっかりしたという経験はありませんか?今回はC#のサンプルコードをVBで活用する方法を説明します。具体的にはそのためにC#からVBの翻訳のポイントを説明し、最後は実際に翻訳を行ってみます。
概要 ・C#とVBは兄弟言語なので、C#のサンプルをVBに翻訳するのは難しくない。 ・機械的な作業でも8割くらいは翻訳ができる。あとの2割はピンポイントでつぶす。 ・キーワードや構文の翻訳早見表 ・具体的な翻訳例 |
VBとC#(読み方:C# = シーシャープ)は兄弟といっていい言語で、言語としての構造や考え方が似ているだけではなく、使用するクラスやフレームワークまで同じです。厳密には.NET Frameworkを使用しないC#というものもあり得るのかもしれませんが現実的にはこの可能性は無視できます。
こういう状況ですから、VBについてわからないことがあって調べ物をするときに、実はC#の情報がとても役に立ちます。
みなさんは経験がないでしょうか?クラスやメソッドの使い方がわからずインターネットで検索してみたらC#のサンプルが見つかったが、VBのサンプルが見つからないというようなことが?
そのときみなさんはどうしていましたか?VBではないのであきらめていたでしょうか?
今回はこのような状況でもC#のサンプルをVBのために役立てる方法を説明します。いくつか覚えることはありますが簡単なことです。
やろうとしているのはC#で書かれたプログラムを簡単にVBに翻訳することです。
VBとC#は基本が一緒ですので、VBである程度のプログラム経験があればC#をゼロから勉強する必要はありません。ここでは知っておくべきいくつかのC#の言語的な特徴をあげて、後で具体例を見ていくことにします。
なお、今回の説明ではC#のコードの9割程度をVBに翻訳できる情報量を目指しています。さすがに10割翻訳するためにはもっと修練を積む必要があります。
VBでは1行1命令のような構造になっていて、どうしても改行を入れたければ「 _」を記述する必要がありますが、C#では逆で「;」をつけるまでが1命令で、改行は単語の区切りであれば自由です。
たとえば、次のbutton1のフォントと文字を変更するプログラムを見てください。
button1.Font = new Font(this.Font.FontFamily, 12, FontStyle.Bold);
button1.Text = "フォント変更!";■リスト1:C#でのフォントの変更の例
途中に出てくるthisはVBで言うとMeです。
この例を改行して次のように書くこともできます。
button1.Font = new Font(this.Font.FontFamily,
12,
FontStyle.Bold);
button1.Text = "フォント変更!";■リスト2:C#では複数行にわたって自由に書くことができる。
長いコードを改行したいときはよくありますが、このように自由に改行できるのはC#のいいところです。
たとえば、VBでは変数を宣言したり使用するときは以下のような書き方をします。
Dim count As Integer
Dim message As String
For i As Integer = 0 To Me.Controls.Count - 1
'何かの処理
Next■リスト3
これと同じ意味のC#のプログラムは次のようになります。
int count;
string message;
for (int i = 0; i <= this.Controls.Count - 1; i++)
{
//何かの処理
}■リスト4
forの書き方がVBと違いますが、これは後で説明します。変数の宣言部分に着目するとDimやAsがとれて型名が前に来るという法則になっていることがわかります。
ただし、型名も微妙にことなっており、VBのIntegerはC#のint、Stringはstringになっています。もっともstringに関しては.NET Frameworkのクラス名がStringなのでStringでも通用します。
この法則にしたがって関数の宣言も次のようになります。
public int GetProductCount(string productCode)
{
//何かの処理
}■リスト5
これと等価なコードをVBで書くとすると次のようになります。
Public Function GetProductCount(ByVal productCode As String) As Integer
'何かの処理
End Function■リスト6
見事に型を指定する部分が前から後になっていることがわかります。
こういう事情なのでC#ではDimとかFunctionとかSubのようなキーワードはつけません。後で説明しますがSubのときは特殊な型であるvoidを使用します。
VBではブロック構造を表現するのに、If 〜 End If、Function 〜 End Function、Class 〜 End Classのように対応するEnd ○○を付けますが、C#ではそれも { と } で表現します。そのため、入れ子が深くなるとどの } が何の終わりなのかVB以上にわかりにくくなってしまいますが・・・。
「//」についてはVBの「'」と同等です。「/* 〜 */」はVBにはない機能でブロックを丸ごとコメントにできます。
10年前にVBにも選択範囲をまるごとコメントにするツールバーのアイコンが追加されたので、ブロックコメントがなくても不便は感じなくなりましたが、それ以前はVBはブロックまるごとコメントにするためにはい行ずつ「'」をつけなくてはいけなかったのでかなり面倒でした。そのときはまだC#はありませんでしたが、前身となるCにも同じブロックコメント機能があったのでうらやましく感じたものです。
public int GetProductCount(string productCode)
{
/*
こうやって書くとこの部分は
何行でもコメントになるんですね!
string message = "これはコメントです!";
*/
}■リスト7:C#のブロックコメント
VBでは引数がないメソッドの呼び出しは( )をつけなくてもいいのですが、C#ではだめです。
たとえば、変数の型名を取得する以下のVBのプログラムは有効です。
Dim count As Integer = 3
Dim message As String
message = count.GetType.FullName
MessageBox.Show(message)■リスト8
このプログラムではGetTypeメソッドをかっこなしで呼び出しています。かっこをつけても構いません。VBではどちらの書き方もできます。
しかし、C#では必ずかっこをつける必要があります。
int count = 3;
string message;
message = count.GetType().FullName;
MessageBox.Show(message);■リスト9
FullNameはプロパティなのでかっこをつけません。
ここでいうメソッドにはコンストラクタも含まれることに注意してください。VBのプログラマは引数なしでNewが使用できるとき ( ) をつけないことが多いですが、C#の世界では必ず ( ) をつけます。
VBメインでためにC系の言語をいじるようなプログラマはわかっていてもついつい == を = を書いてしまいます。
よくよく考えるとVBの「=」には代入と比較の2つの意味があるのですが、C#の「=」には代入の意味しかなく、比較する場合は「==」を使います。これは主にif文の中で問題になります。
次のプログラムはフォームに配置されているコントロールの数を数えるVBのプログラムです。もし、コントロールの数が1個だけならばメッセージを表示します。
Dim count As Integer
count = Me.Controls.Count
If count = 1 Then
MessageBox.Show("コントロールが1つしかありませんね!")
End If■リスト10
このプログラムでは = が2つ登場しますが、最初の = は代入、次の = は比較の意味で使用しています。
これと等価なプログラムをC#で書くと次のようになります。
int count;
count = this.Controls.Count;
if (count == 1)
{
MessageBox.Show("コントロールが1つしかありませんね!");
}■リスト11
C#ではメソッドの呼び出しはVBと同じで ( ) を使うのですが、配列やコレクションの要素にアクセスするときはVBでは ( ) を使うところが [ ] になります。
たとえば、以下のプログラムはVBで記述したものです。
Dim names As New List(Of String)
names.Add("アメンボ")
names.Add("イノシシ")
names.Add("ウマ")
Dim secondName As String
secondName = names(1)
MessageBox.Show(secondName)■リスト12
これと等価なプログラムをC#で書くと次のようになります。
List<string> names = new List<string>();
names.Add("アメンボ");
names.Add("イノシシ");
names.Add("ウマ");
string secondName;
secondName = names[1];
MessageBox.Show(secondName);■リスト13
これまでの例ですでに気がつかれたと思いますが、C#では大文字と小文字を厳密に区別します。たとえば、C#ではCountとcountは違う変数です。
また、構文でも if と書くところを If と書くことはできません。
単純なことですが重要な違いなので注意です。
特に昔堅気のプログラマは型名を小文字にした変数名を使ったりします。VBに翻訳するときはなんか工夫する必要があるかもしれません。
VBでは自作のクラスのコンストラクタを作るにはNewという名前のSubプロシージャを定義しますが、C#ではクラスメイト同じ名前で戻り値の指定がないプロシージャがコンストラクタになります。
たとえば、VBで以下のようなコンストラクタを書いたとします。
Public Class TestClass
Dim X As Integer
Public Sub New()
X = 100
End Sub
End Class■リスト14
これと等価なプログラムはC#では以下のとおりです。
public class TestClass
{
int X;
public TestClass()
{
X = 100;
}
}■リスト15
C#のキーワードや記号のVBでの翻訳例を表にまとめておきます。必要に応じて参照してください。
C#とVBは構文も似ています。C#にもif文やdoループなどがありますが、書き方が少し違うので、代表的なものだけまとめておきます。こういった点は必要に応じて見ればよいので、神経質にならなくてもよいでしょう。MSDNライブラリのC#リファレンスも参考になります。
ここではC#のコードを等価なVBのコードに置き換える例を示すだけでC#のコードやキーワードの意味・使用方法までは踏み込まないことにします。
文章で表現すると長くなってしまいましたので、C#からVBに翻訳するときの方針を簡単にまとめておきます。
手順1.まずはコメントを翻訳します。つまり、 // や /* */ を ' に置き換えます。
手順2.; セミコロンをとります。このとき、C#で改行されている個所をVB流に「 _」を付けるか1行にまとめるかします。
手順3.宣言をなおします。つまり、int X見たいになっている部分を Dim X As Integerのように書き換えます。
このとき、宣言の中にあるvoidは削除します。関数の場合はvoidの部分にsubを入れます。
手順4.ジェネリックを翻訳します。つまり、<型名>が使われている個所を(Of 型名)にします。
手順5.ブロック構造を翻訳します。つまり、if { } や for { }などを If 〜 End If、 For 〜 Nextなどに書き換えます。
手順6.構文を翻訳します。if、for、foreachなどの構文をVBに翻訳します。
手順7.細かいところを直します。つまり、thisをMeにしたり、[ ] を ( ) にしたりします。
この段階で翻訳作業の8割は完了です。ほとんど機械的にできます。
あとは、残っている部分を個別につぶしていきます。MSDNやインターネットで調べる必要があるかもしれません。
それでは、最後に具体例としてIEからイベントの通知を受け取るプログラムをVBで作成してみます。
すでにC#のサンプルコードを入手しているという仮定で、VBに翻訳してみましょう。
このC#のクラスは、RunメソッドでIEを開いてホームページを表示します。そして、ユーザーがリンクをクリックするなどして別のページに移るとNavigateCompletedイベントを発生させます。本当はもっといろいろなイベントや情報が取得できるのですが、翻訳の練習ということで簡単な機能だけに絞りました。
このプログラムを実行するにはC#でもVBでもCOMオブジェクトの「Microsoft Intenet Controls」への参照設定が必要になります。
それから、Vistaで使用する場合はIE7の保護モードをオフにする必要があります。[ツール]メニューの[インターネット オプション]でセキュリティ画面を表示させて、インターネットゾーンと、ローカルイントラネットゾーンの保護モードをオフにしてください。ただし、この設定をするとセキュリティ上問題があるかもしれないので気を付けてください。実験が終わったら元に戻してください。
さて、C#のコードは次のようなものです。このコードはMSDNライブラリに載っていたものを私が機能を削ってシンプルにしたものです。
namespace IEOperation { using System; using System.Runtime.InteropServices; using SHDocVw; public class Explorer { static private SHDocVw.InternetExplorer m_IExplorer = null; static private IWebBrowserApp m_WebBrowser = null; public delegate void NavigateCompletedHandler(object sneder,EventArgs e); public event NavigateCompletedHandler NavigateCompleted; public void Run() { //■「Navigate Complete」を取得できるように構成 m_IExplorer = new SHDocVw.InternetExplorer(); if (m_IExplorer == null) return; //1.Navigate Complete event DWebBrowserEvents2_NavigateComplete2EventHandler ncd = new DWebBrowserEvents2_NavigateComplete2EventHandler(OnNavigateComplete); m_IExplorer.NavigateComplete2 += ncd; //■IEを開いてホームページを表示 try { m_WebBrowser = (IWebBrowserApp)m_IExplorer; m_WebBrowser.Visible = true; m_WebBrowser.GoHome(); } catch (Exception sE) { } } //ページが遷移したとき NavigateCompletedイベントを発生させる。 public void OnNavigateComplete(Object o1, ref Object o2) { NavigateCompleted(this,null); } } } |
■リスト16:C#版の完全なコード
VBに移植するために、まずはVBのプロジェクトを作成しましょう。今回はWindowsアプリケーションを使用することにします。名前はC#のコードの名前空間が「IEOperation」になっているのでそれをそのまま使うことにします。別に違う名前を付けたければそれでも構いません。
それから、参照設定でさきほどの「Microsoft Internet Controls」への参照の追加も忘れないでください。これはCOMですので、.NETの一覧には表示されていません。ページをCOMに切り替えてから探してください。
プロジェクトにExplorerというクラスを追加しましょう。このクラスの名前はC#のサンプルコードの中のクラス名から採りました。これも好きな名前にしておいてもよいのですが、クラス名レベル以下は混乱を避けるために同じ名前に翻訳することをお勧めします。
ExplorerクラスにはVBが自動生成する何行かのコードは削除してC#のコードをそのまま貼り付けてしまってください。
いっぱいエラーがでますが当然ですね。
さぁ、いよいよ翻訳スタートです。まずはさきほどの手順1から片づけましょう。つまり、コメント行を ' に変えます。それから手順2のセミコロン除去作業と複数行まとめ作業もやってしまいましょう。
ここまでで次のようになります。
Namespace
IEOperation { using System using System.Runtime.InteropServices using SHDocVw Public Class Explorer { static private SHDocVw.InternetExplorer m_IExplorer = null static private IWebBrowserApp m_WebBrowser = null public delegate void NavigateCompletedHandler(object sneder,EventArgs e) public event NavigateCompletedHandler NavigateCompleted public void Run() { '■「Navigate Complete」を取得できるように構成 m_IExplorer = new SHDocVw.InternetExplorer() if (m_IExplorer == null) return '1.Navigate Complete event DWebBrowserEvents2_NavigateComplete2EventHandler(ncd) = new DWebBrowserEvents2_NavigateComplete2EventHandler(OnNavigateComplete) m_IExplorer.NavigateComplete2 += ncd '■IEを開いてホームページを表示 try { m_WebBrowser = (IWebBrowserApp)m_IExplorer m_WebBrowser.Visible = true m_WebBrowser.GoHome() } catch (Exception sE) { } } 'ページが遷移したとき NavigateCompletedイベントを発生させる。 public void OnNavigateComplete(Object o1, ref Object o2) { NavigateCompleted(this,null) } } } |
■リスト17:手順1.コメント、手順2.セミコロン除去を実行した段階
インデントは私が少し整えましたが、本物はもっと乱れているはずです。
真ん中あたりにあるDWebBrowserEvemt2...という長い行はC#では2行になっていますが、VBではまとめて1行にしてしまいます。長いのが嫌いな人は「 _」を使用して2行にわけたままでもかまいません。
このくらいではまだVBのプログラムの感じがしませんね。
次は手順3に従って宣言を直します。ジェネリックはないので手順4は飛ばして、手順5のブロック構造のVB化もやってしまいましょう。
Namespace
IEOperation using System using System.Runtime.InteropServices using SHDocVw Public Class Explorer Private Static m_IExplorer As SHDocVw.InternetExplorer = null Private Static m_WebBrowser As IWebBrowserApp = null Public Delegate Sub NavigateCompletedHandler(ByVal sneder As Object, ByVal e As EventArgs) Public Event NavigateCompleted As NavigateCompletedHandler Public Sub Run() '■「Navigate Complete」を取得できるように構成 m_IExplorer = New SHDocVw.InternetExplorer() if (m_IExplorer == null) Return End If '1.Navigate Complete event Dim ncd As DWebBrowserEvents2_NavigateComplete2EventHandler = New DWebBrowserEvents2_NavigateComplete2EventHandler(OnNavigateComplete) m_IExplorer.NavigateComplete2 += ncd '■IEを開いてホームページを表示 Try m_WebBrowser = (IWebBrowserApp)m_IExplorer m_WebBrowser.Visible = True m_WebBrowser.GoHome() catch ( sE as Exception) End Try End Sub 'ページが遷移したとき NavigateCompletedイベントを発生させる。 public sub OnNavigateComplete( o1 as Object, ref o2 as Object) NavigateCompleted(this, null) End Sub End Class End Namespace |
■リスト18:手順3.宣言の修正、手順5.ブロック構造の修正を実行した段階
{ } がなくなってだいぶVBらしくなってきました。もう雰囲気はVBですね。良く見るとキーワードByValがついている個所がありますが、これはVBが自動的につけてくれるので自分でつける必要はありません。
それから、なれてないと戸惑うと思うので簡単に書いておきますが、C#の以下の記述はNavigateCompletedHander型のイベントNavigateCompletedを宣言している個所です。
public event NavigateCompletedHandler NavigateCompleted; |
■リスト19
変数の宣言と型名が前に来ているので、VB化すると次のようになります。
Public Event NavigateCompleted As NavigateCompletedHandler |
■リスト20
intとかstringだとすぐにわかると思いますが、このようなオブジェクト型の場合はぱっと見でわけがわからないような印象を持ってしまう方もいるかもしれませんね。でも、法則どおりAsを付けて型名を後ろに持って行くだけでいいのです。
それから、Dim ncd As ...の行ですが、翻訳前はかっこがついていてメソッド呼び出しのようになっていますが、実はこのかっこはVBが勝手につけたもので、一番最初の状態をみると単なる変数の宣言なんです。このように時折VBがかってにかっこをつけたりしますので惑わされないように注意が必要です。
次には手順6に従って構文を翻訳します。このサンプルではIfとTryの2つがあります。それから、手順7にしたがって代表的なキーワードや記号も置き換えてしまいましょう。これには「3.キーワード・記号翻訳早見表」を使ってください。
Namespace
IEOperation imports System imports System.Runtime.InteropServices imports SHDocVw Public Class Explorer Private Shared m_IExplorer As SHDocVw.InternetExplorer = Nothing Private Shared m_WebBrowser As IWebBrowserApp = Nothing Public Delegate Sub NavigateCompletedHandler(ByVal sneder As Object, ByVal e As EventArgs) Public Event NavigateCompleted As NavigateCompletedHandler Public Sub Run() '■「Navigate Complete」を取得できるように構成 m_IExplorer = New SHDocVw.InternetExplorer() If m_IExplorer = Nothing Then Return End If '1.Navigate Complete event Dim ncd As DWebBrowserEvents2_NavigateComplete2EventHandler = New DWebBrowserEvents2_NavigateComplete2EventHandler(OnNavigateComplete) m_IExplorer.NavigateComplete2 += ncd '■IEを開いてホームページを表示 Try m_WebBrowser = (IWebBrowserApp)m_IExplorer m_WebBrowser.Visible = True m_WebBrowser.GoHome() Catch sE As Exception End Try End Sub 'ページが遷移したとき NavigateCompletedイベントを発生させる。 Public Sub OnNavigateComplete(ByVal o1 As Object, ByRef o2 As Object) NavigateCompleted(Me, Nothing) End Sub End Class End Namespace |
■リスト21:手順7完了時点
これでほとんどVB化されました。このように定型的な処理だけでここまでの状態にできます。
でも、まだエラーがいっぱいでているのが気になりますか?
この例ではImportsの位置が悪いのでエラーがたくさんでてしまいます。
ここからの翻訳はケースバイケースになりますが、まずはNamespace 〜 End Namespaceを削除してみましょう。VBでは通常はNamespaceを自分で宣言することはしませんし、これのせいでImportsの位置が悪くなって こともあるのでだいぶ状況が改善されます。
あとは、1つずつつぶしていきます。
まず、ここでエラーが出ていますね?
If
m_IExplorer = Nothing
Then Return End If |
■リスト22
VBでは変数の内容がNothingであるか確認するときにはIsNothing関数を使用するようにしましょう。
つまり、次のようになります。
If
IsNothing(m_IExplorer)
Then Return End If |
■リスト23
それから、行が長くて気が付きにくいのですが、この行でエラーがでているはずです。
Dim ncd As DWebBrowserEvents2_NavigateComplete2EventHandler = New DWebBrowserEvents2_NavigateComplete2EventHandler(OnNavigateComplete) |
■リスト24
何が悪いのか考えてみると、かっこのなかにメソッドを入れていますよね?VBではメソッドそれ自体を値のように引数にしたりするにはAddressOf演算子を使用して明示する必要があります。これはちゃんとVBのことを知っていないとちょっと厳しいかもしれませんね。
次のようになります。
Dim ncd As DWebBrowserEvents2_NavigateComplete2EventHandler = New DWebBrowserEvents2_NavigateComplete2EventHandler(AddressOf OnNavigateComplete) |
■リスト25
次は少しC#の知識が必要です。
m_IExplorer.NavigateComplete2 += ncd |
■リスト26
これはC#ではイベントハンドラの割り当てを意味しています。VBではイベントハンドラを動的に割り当てるにはAddHandlerを使用します。
この箇所は次のようになります。
AddHandler m_IExplorer.NavigateComplete2, AddressOf OnNavigateComplete |
■リスト27
次もC#の知識が必要になります。C#ではよくやることなのですが次のコードは型変換を意図しているのです。
m_WebBrowser = (IWebBrowserApp)m_IExplorer |
■リスト28
つまり、変数m_IExplorerをIWebBrowserApp型に変換してm_WebBrowserに代入するという処理です。VBでは型変換にはDirectCastかCTypeを使用します。
m_WebBrowser = DirectCast(m_IExplorer, IWebBrowserApp) |
■リスト29
最後は次のコードです。
NavigateCompleted(Me, Nothing) |
■リスト30
この行はNavigateCompletedイベントを発生させようとしていますから、VBではRaiseEventを使用する必要があります。
RaiseEvent NavigateCompleted(Me, Nothing) |
■リスト31
さて、これですべてのエラーがなくなりました。もちろん見かけ上のエラーがなくなっただけで完成というわけではありませんが、今回は特に問題なく使用できるようになります。
参考に完成版のコードを載せておきます。
Imports
System Imports System.Runtime.InteropServices Imports SHDocVw Public Class Explorer Private Shared m_IExplorer As SHDocVw.InternetExplorer = Nothing Private Shared m_WebBrowser As IWebBrowserApp = Nothing Public Delegate Sub NavigateCompletedHandler(ByVal sneder As Object, ByVal e As EventArgs) Public Event NavigateCompleted As NavigateCompletedHandler Public Sub Run() '■「Navigate Complete」を取得できるように構成 m_IExplorer = New SHDocVw.InternetExplorer() If IsNothing(m_IExplorer) Then Return End If '1.Navigate Complete event Dim ncd As DWebBrowserEvents2_NavigateComplete2EventHandler = New DWebBrowserEvents2_NavigateComplete2EventHandler(AddressOf OnNavigateComplete) AddHandler m_IExplorer.NavigateComplete2, AddressOf OnNavigateComplete '■IEを開いてホームページを表示 Try m_WebBrowser = DirectCast(m_IExplorer, IWebBrowserApp) m_WebBrowser.Visible = True m_WebBrowser.GoHome() Catch sE As Exception End Try End Sub 'ページが遷移したとき NavigateCompletedイベントを発生させる。 Public Sub OnNavigateComplete(ByVal o1 As Object, ByRef o2 As Object) RaiseEvent NavigateCompleted(Me, Nothing) End Sub End Class |
■リスト32:VB版の完全なコード
フォームに次のようなプログラムを書いて動作を確認してみてください。Vistaの方はさきほど書いたように保護モードをオフにしてないとうまく動きません。
Public
Class Form1 Dim WithEvents exp As New Explorer Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click exp.Run() End Sub |
Private
Sub exp_NavigateCompleted(ByVal
sneder As Object,
ByVal e As
System.EventArgs) Handles
exp.NavigateCompleted MsgBox("ページ遷移しました!") End Sub End Class |
■リスト24:完成版をテストするためのフォーム側のコード
今回私はC#のサンプルをVBで活用する方法を説明しました。そしてそのための翻訳作業はそれほど難しくないことを理解していただけたと思います。実際にやってみるとピンポイントで何箇所か難しい箇所がでてくることはありますが、9割程度の翻訳は今回の方法でうまくいきますし、私たちの目的は「C#をVBに翻訳すること」ではなく「C#のサンプルをVBで活用すること」なのですから大きな問題にはならないでしょう。それにC#の機能をそのまま使いたいのであれば、わざわざ翻訳する必要はなくC#のままでVBから呼び出せばいいわけです。
なれてくれば逐一翻訳しなくてもC#のサンプルを頭の中でVBに役立つ形に整理できるようになるでしょう。
これで、C#のサンプルが活用できるようになれば情報量は2倍になるかもしれません。大いに役立ててください。