I am normally a C# guy, so I used Linqpad to demonstrate this behavior with this code:
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())
Putting 0 in the object i forces the box, just like calling the method.
The results, as the question indicates are:
a=True
b=False
The IL generated is:
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
As you can see, the difference is in what implementation of Equals is called. In the first case, the Int32.Equals (Int32 is a CLR structure) is called. This is a value equivilence check.
In the second instance, the Object.Equals is called which does a reference comparison--do the references point at the same object?
You should not expect the same behavior from these methods.
I would suggest that you need to ask yourself why are you comparing integers to Nothing? They can NEVER be Nothing, but objects can, so the system's behavior is entirely appropriate.
Again, an Integer CANNOT be Nothing. It is almost meaningless to compare it to Nothing--except that the CLR type system has a a contract that Equals has to return something.
So what you should do is reanalyze what you are doing so you are never comparing plain integers to Nothing, and never forcing the false box by the formal parameters of your procedure or function. Instead, pass them as Integer by value so boxing does not happen.
If you absolutely positively have to do this, have two overloads.
Private Function EqualsNothing(ByVal item As Integer) As Boolean
Private Function EqualsNothing(ByVal item As Object) As Boolean
CLR semantics will select the non-boxed integer one preferntially.
I am writing this at 3:00 AM so not checking the VB syntax details above, since this is in response to comment discussion.
Or just force the thing to be unboxed:
Private Function EqualsNothing(ByVal item As Object) As Boolean
Dim int As Integer = item
Return int.Equals(Nothing)
End Function
Again, its late--syntax not checked. The risk with this is that if the object is NOT an integer, you will get an exception.