2015年1月30日

VB.NET 匿名デリゲートと 3 項演算子で実行時エラー

下記は、何の問題もなさそうでコンパイル可能なコードだが、実行時エラーが発生する。
[コード]

Module TestDelegateIf
    Sub Main()
        Dim text As String = Nothing
        Dim fn As Func(Of Integer) = If(text Is Nothing, Nothing, Function() text.Length)
    End Sub
End Module
[結果]
ハンドルされていない例外: System.ArgumentException: インスタンス メソッドへのデリゲートに null の 'this' を指定することはできません。
   場所 System.MulticastDelegate.CtorClosed(Object target, IntPtr methodPtr)
   場所 TestDelegateIf.Main()

3 項演算子を使っているのに、Function() text.Length の部分が実行されているっぽく??????
Function ラムダ式だけでなく、Sub ラムダ式でも同じ現象が発生する。

解決手段?

3 項演算子でなく If 文を使えばエラーは起きない。
匿名デリゲートを Func(Of Integer) に代入してもエラーは起きない。
[正常コード1]

Module TestDelegateIf
    Sub Main()
        Dim text As String = Nothing

        ' If を使用
        Dim fn As Func(Of Integer)
        If text Is Nothing Then
            fn = Nothing
        Else
            fn= Function() text.Length
        End If

        ' 匿名デリゲートの代入
        Dim fn_ = Function() text.Length
        fn = fn_
    End Sub
End Module

匿名デリゲートを使わない方法もエラーは起きない。
※ C# だと匿名デリゲートが存在しないため、これと同等のコードになる。
[正常コード2]

Module TestDelegateIf
    Sub Main()
        Dim text As String = Nothing
        Dim fn = If(text Is Nothing, Nothing, New Func(Of Integer)(Function() text.Length))
    End Sub
End Module

まとめ

この現象は、たぶんコンパイラのバグに該当するものだと思われる。
VB の匿名デリゲートは便利だが、同時に無効化する Option が欲しい。というかあった方がいい。

検証環境

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