C#ユーザーがVBの遅延バインディングに驚いた話など
色々あって、Visual Studio 2008でVBをやっています。
触ってみた結果、多数のスタティックメソッドや「改行にアンダーバー必須」といった文法関連など色々なC#との使い勝手の違いを感じましたが、一番違いに驚いたのは下記コードの動作です。
Dim testobj As Object 'オブジェクト型の変数に日付型を代入 testobj = DateTime.Now 'Objectクラスが持っていない「Month」プロパティを、遅延バインディングで使える Console.WriteLine(testobj.Month & "月")
思い起こせば、VB6の頃は当たり前のように遅延バインディングを使ったコードを書いていましたが、今見るとtestobjにMonthプロパティがないクラスのインスタンスを入れると実行時エラーが出せてしまう事から、少々おっかない印象を受けてしまいます。
なお上記のコードをC#で動くように書くと、下記のようになります。
object testobj; testobj = DateTime.Now; //TypeクラスのGetPropertyメソッドでプロパティ情報を取得し、オブジェクトのプロパティ値取得を行う Console.WriteLine(testobj.GetType().GetProperty("Month").GetValue(testobj).ToString() + "月");
リフレクションを用いてプロパティ情報を取得した後、プロパティの実際の値を取得する流れになります。
少々冗長な気もしますが、リフレクションを使うと下記のように、変数testobjのプロパティの有無をチェックする事が容易です。
object testobj; testobj = DateTime.Now; //Monthプロパティを取得 System.Reflection.PropertyInfo prop = testobj.GetType().GetProperty("Month"); if (prop != null) {//testobjに入ったオブジェクトに、Monthプロパティが存在する場合にのみ処理が実行される Console.WriteLine(prop.GetValue(testobj).ToString() + "月"); }
プロパティの有無をチェックすることで、実行時エラーを防げます。
もちろんVBでも、リフレクションを用いてプロパティの有無をチェックできます。
Dim testobj As Object testobj = DateTime.Now 'リフレクションでMonthプロパティの情報を取得 Dim prop As System.Reflection.PropertyInfo = testobj.GetType().GetProperty("Month") If (prop <> Nothing) Then 'testobjにMonthプロパティが存在する場合のみ、処理が実行される Console.WriteLine(testobj.Month & "月") End If
コードは長くなりますが、遅延バインディングの対象となるオブジェクト型の変数に何が入ってくるかわからない時にはぜひこのチェックは行ったほうが良さそうです。
遅延バインディングを止めて、きちんと型チェックをしてから実行したい場合は下記のような感じで。
Option Strict On … Dim testobj As Object testobj = DateTime.Now 'リフレクションでMonthプロパティの情報を取得 Dim prop As System.Reflection.PropertyInfo = testobj.GetType().GetProperty("Month") If (prop <> Nothing) Then 'testobjにMonthプロパティが存在する場合のみ、処理が実行される Console.WriteLine(prop.GetValue(testobj).ToString() & "月") End If
なお、C#4.0からはdynamic型が使えるため、C#でも遅延バインディング的な書き方が可能です。
dynamic testobj;
testobj = DateTime.Now;
Console.WriteLine(testobj.Month + "月");