更新:
下面的答案似乎特定于System.Object
扩展的情况。当扩展其他类时NullReferenceException
,VB 中没有。
由于此Connect 问题中所述的原因,此行为是设计使然:
VB 允许您调用定义在 Object 上的扩展方法,但前提是该变量不是静态类型为 Object。
原因是 VB 还支持后期绑定,如果我们在调用声明为 Object 的变量时绑定到扩展方法,那么无论您是在尝试调用扩展方法还是其他后期方法,都是模棱两可的——具有相同名称的绑定方法。
理论上,我们可以通过 Strict On 来实现这一点,但 Option Strict 的原则之一是它不应该改变代码的语义。如果允许这样做,那么更改您的 Option Strict 设置可能会导致静默重新绑定到不同的方法,从而导致完全不同的运行时行为。
例子:
Imports System.Runtime.CompilerServices
Module Extensions
<Extension()> _
Public Function IsNull(ByVal obj As Object) As Boolean
Return obj Is Nothing
End Function
<Extension()> _
Public Function IsNull(ByVal obj As A) As Boolean
Return obj Is Nothing
End Function
<Extension()> _
Public Function IsNull(ByVal obj As String) As Boolean
Return obj Is Nothing
End Function
End Module
Class A
End Class
Module Module1
Sub Main()
' works
Dim someString As String = Nothing
Dim isStringNull As Boolean = someString.IsNull()
' works
Dim someA As A = Nothing
Dim isANull As Boolean = someA.IsNull()
Dim someObject As Object = Nothing
' throws NullReferenceException
'Dim someObjectIsNull As Boolean = someObject.IsNull()
Dim anotherObject As Object = New Object
' throws MissingMemberException
Dim anotherObjectIsNull As Boolean = anotherObject.IsNull()
End Sub
End Module
事实上,VB 编译器会创建一个后期绑定调用,以防您的变量静态类型为Object
:
.locals init ([0] object exampleObject, [1] bool exists)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldnull
IL_0004: ldstr "IsNull"
IL_0009: ldc.i4.0
IL_000a: newarr [mscorlib]System.Object
IL_000f: ldnull
IL_0010: ldnull
IL_0011: ldnull
IL_0012: call
object [Microsoft.VisualBasic]Microsoft.VisualBasic.
CompilerServices.NewLateBinding::LateGet(
object,
class [mscorlib]System.Type,
string,
object[],
string[],
class [mscorlib]System.Type[],
bool[])
IL_0017: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::NotObject(object)
IL_001c: call bool [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToBoolean(object)
IL_0021: stloc.1