私は通常 C# を使用しているので、Linqpad を使用して、このコードでこの動作を示しました。
dim a as object
dim b as object
dim i as object
a = 0.Equals(Nothing)
Console.WriteLine("a={0}", a.ToString())
i = 0
b = i.Equals(Nothing)
Console.WriteLine("b={0}", b.ToString())
オブジェクト i に 0 を入れると、メソッドを呼び出すのと同じようにボックスが強制されます。
質問が示すように、結果は次のとおりです。
a=True
b=False
生成される IL は次のとおりです。
IL_0001: ldc.i4.0
IL_0002: stloc.3
IL_0003: ldloca.s 03
IL_0005: ldc.i4.0
IL_0006: call System.Int32.Equals
IL_000B: box System.Boolean
IL_0010: stloc.0
IL_0011: ldstr "a={0}"
IL_0016: ldloc.0
IL_0017: callvirt System.Object.ToString
IL_001C: call System.Console.WriteLine
IL_0021: nop
IL_0022: ldc.i4.0
IL_0023: box System.Int32
IL_0028: stloc.2
IL_0029: ldloc.2
IL_002A: ldnull
IL_002B: callvirt System.Object.Equals
IL_0030: box System.Boolean
IL_0035: stloc.1
IL_0036: ldstr "b={0}"
IL_003B: ldloc.1
IL_003C: callvirt System.Object.ToString
IL_0041: call System.Console.WriteLine
IL_0046: nop
ご覧のとおり、違いは Equals のどの実装が呼び出されるかです。最初のケースでは、Int32.Equals (Int32 は CLR 構造体) が呼び出されます。これは値の等価性チェックです。
2 番目のインスタンスでは、参照比較を行う Object.Equals が呼び出されます。参照は同じオブジェクトを指していますか?
これらのメソッドから同じ動作を期待するべきではありません。
なぜ整数を Nothing と比較するのかを自問する必要があることをお勧めします。それらは決してNothingになることはできませんが、オブジェクトはできるため、システムの動作は完全に適切です。
繰り返しますが、Integer を Nothing にすることはできません。それを Nothing と比較してもほとんど意味がありません。ただし、CLR 型システムには、Equals が何かを返さなければならないというコントラクトがあることを除きます。
したがって、何をしているのかを再分析して、単純な整数を Nothing と比較したり、プロシージャまたは関数の仮パラメータによって false ボックスを強制したりしないようにする必要があります。代わりに、ボックス化が起こらないように値で整数として渡します。
絶対にこれを行う必要がある場合は、2 つのオーバーロードを用意してください。
Private Function EqualsNothing(ByVal item As Integer) As Boolean
Private Function EqualsNothing(ByVal item As Object) As Boolean
CLR セマンティクスは、ボックス化されていない整数を優先的に選択します。
これを午前 3:00 に書いているので、上記の VB 構文の詳細はチェックしていません。
または、強制的に箱から出します:
Private Function EqualsNothing(ByVal item As Object) As Boolean
Dim int As Integer = item
Return int.Equals(Nothing)
End Function
繰り返しますが、遅い構文はチェックされていません。これに伴うリスクは、オブジェクトが整数でない場合に例外が発生することです。