2014年4月9日

VB.NET の Object 型からは拡張メソッド使用不可

Object 型から拡張メソッドを使うことは滅多にないだろうけど、たまたまそのようなコードを書いて、拡張メソッドが使えなくてビビったことがある。
C#.NET にこの問題はなく、VB.NET 固有の問題になる。

  • 拡張メソッド

public static class Extensions
{
    public static int GetHashCodeSafely<T>(this T source)
    {
        return source == null ? 0 : source.GetHashCode();
    }
}
  • C#.NET から利用

var num = 1;

// 問題無し
var hash = num.GetHashCodeSafely();
// 問題無し
hash = ((object)num).GetHashCodeSafely();
  • VB.NET から利用

Dim num = 1

' 問題無し
Dim hash = num.GetHashCodeSafely()
' コンパイル不可「Option Strict On では、遅延バインディングを使用できません。」
hash = DirectCast(num, Object).GetHashCodeSafely()

遅延バインディングとは、VB.NET の機能で「Option Strict Off」時に Object 型に対してその定義にないメソッドやプロパティを呼べること。
.NET 4.0 からの dynamic 型と同じようなことが、VB.NET では Object 型に対して可能。

Option Strict Off

Dim text As String = ""
Dim obj As Object = text
Console.WriteLine(obj.Length)  ' 0 が出力される
Console.WriteLine(obj.Lengths) ' Lengths メンバは存在しないため、実行時エラー

つまり、VB.NET で Object 型から生えてるものは、自身のメンバを除いてすべて遅延バインディングと判断される。
そのため、呼び出し方法がかぶる拡張メソッドは使えない。(初期の VB.NET 開発時に拡張メソッドなんて想定してないだろうし・・・)
「Option Strict On」の時のみ Object 型に対する拡張メソッドを有効にできれば理想だけど、たぶんコンパイラの修正が難しいのだろう。

今後、この問題が改良される可能性は低いだろうから、Object 型に対しては、あきらめて普通の静的メソッドを使うしかない。

検証環境

Windows 7 64bit/Visual Studio 2010 SP1/.NET 4.0

参考URL

0 件のコメント:

コメントを投稿