佐々木屋

技術的なことから趣味まで色々書きます

遅延バインディング

バインディング(型を結びつけること)には事前バインディングと遅延バインディングの2種類あります。これもC#VB.NETで微妙に動作(というかお作法)が違います。

はじめに事前バインディングと遅延バインディングの違いを簡単に説明します。読んで字のごとくなのですが、事前バインディングは宣言時に型を指定して使用する方法、遅延バインディングは実行時に初めてObject型変数に対して代入される型が決定する方法です。

'事前バインディング
Dim obj As DateTime '←ここで型が決定
obj = DateTime.Today
Console.WriteLine(obj.Month)
'遅延バインディング
Dim obj As Object
obj = DateTime.Today '←ここで型が決定
Console.WriteLine(obj.Month)

C#ではそもそもこのような書き方ができません。


遅延バインディングはかつてVB6、VBAなどで当たり前のように使われてきました。遅延バインディングはある意味負の遺産と言ってもよいでしょう。また、レガシー機能というだけでなく、実際速度の低下やバグの温床(ランタイムエラー)などになりやすいので、VB.NET環境下においては推奨された手法ではありません。しかし、VB.NETには「Option Strict Off」という機能があります。この場合はほぼVB6スタイルでコードを書くことができますので、遅延バインディングで書いてもエラーは起きません。
sasaki816.hatenablog.com


しかし、「Option Strict On」の状態だと、暗黙の型変換は使用出来なくなる為、当然遅延バインディングも使用出来なくなります。
そもそも論として、遅延バインディングはよほどの事(アンマネージリソースの呼び出しとか)が無い限り使用すべきではないのですが、状況によっては使わざるを得ない場合もあるのです。

例えばVB6のレガシーコードスタイルが強いVB.NETのコードを引き継いで使用したりする場合です。こういった場合、一部を除外しようとすると余りにも影響が大きい事があります。まぁ「影響が大きい=面倒」ということから遅延バインディングで書いているんでしょうけど。


以下は遅延バインディングを使用した場合の回避方法です。手法はたくさんありますが、代表的なものを3つ(+1つおまけ)だけ紹介します。

キャストする

通常は匿名メソッド、ラムダ式を利用した場合によく使う手法ですが、遅延バインディングの回避としても有用です。但し例外が起こりやすいので、忘れずに例外処理を入れましょう。また、キャストする前に型が正しいかどうかの確認を入れるとよいです。

object obj;
obj = DateTime.Today;
if (obj is DateTime) {
    Console.WriteLine(((DateTime)obj).Month);
}
Dim obj As Object
obj = DateTime.Today
If TypeOf obj Is System.DateTime Then
    Console.WriteLine(CType(obj, DateTime).Month)
End If


リフレクションを使う

リフレクションを使ってプロパティを取得、実行します。回避方法としてはこの方法が一番安全です。

object obj;
obj = DateTime.Today;
System.Reflection.PropertyInfo pro = obj.GetType().GetProperty("Month");
if (obj != null) {
    Console.WriteLine(pro.GetValue(obj).ToString());
}
Dim obj As Object
obj = DateTime.Today
Dim pro As System.Reflection.PropertyInfo = obj.GetType().GetProperty("Month")
If Not pro Is Nothing Then
    Console.WriteLine(pro.GetValue(obj).ToString())
End If


型推論を使う(.NET Framework3.5以上)

これはLINQや局所的な部分であれば有用ですが、スコープが大きすぎる場合は使用してはいけません。

var obj = DateTime.Today;
if (obj != null) {
    Console.WriteLine(obj.Month);
}
Dim obj = DateTime.Today
If Not obj = Nothing Then
    Console.WriteLine(obj.Month)
End If


dynamic型を使う(C#のみ)

.NET Framework4.0から動的型付け変数として新しくdynamic型が登場しました。これによって遅延バインディングで書けるようになっています。但し、VB.NETの遅延バインディングと同様であまりおすすめしません。

dynamic obj;
obj = DateTime.Today;
Console.WriteLine(obj.Month);



状況に応じて使い分けて下さい。しつこいようですが、一番のおすすめは「遅延バインディングしない」です。