Reputation: 4975
See the following code:
Private Function EqualsNothing(ByVal item As Object) As Boolean
Return item.Equals(Nothing)
End Function
Console.WriteLine(0.Equals(Nothing)) ' True
Console.WriteLine(EqualsNothing(0)) ' False
How do I avoid Equals
from returning something different after boxing structures? Is there some way to call the original Equals
implementation?
I know I can use the =
operator in this case, but EqualsNothing
is supposed to work with both classes and structures. The =
operator will not work with classes in VB.NET, and it will also not work with structures that not have implemented this operator. Equals
does work with everything, but as I demonstrated above, Equals
doesn't return the same thing after boxing.
So, how should I rewrite EqualsNothing
so that it works with classes and structures?
Edit: I tried making EqualsNothing
generic, but that did not help.
Upvotes: 0
Views: 154
Reputation: 11216
I'm not sure this will work in all cases, but you might try this generic method:
Sub Main
Console.WriteLine(0.Equals(Nothing)) ' True
Console.WriteLine(EqualsNothing(0)) 'True
End Sub
Private Function EqualsNothing(Of T)(ByVal item As T) As Boolean
Dim i As T = Nothing
Return (item.Equals(i))
End Function
Upvotes: 1
Reputation: 3398
Use the magic of typed objects to you're advantage.
public function Compare(objLeft as Object,objRight as Object) as integer
If TypeOf (objLeft) Is Integer Then
return Cint(objLeft) = Cint(objRight)
ElseIf TypeOf (objLeft) Is DateTime Then
'Your implementation here
ElseIf TypeOf (objLeft) Is String Then
'Your implementation here
End If
end function
This is simply a question of de-boxing the objects but can be extended to support any type you use. Just be smart and place this functonality in a shared object compare so its not copy pasted everywhere.
Upvotes: 0
Reputation: 1708
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.
Upvotes: 5
Reputation: 728
Instead of using Equals, you can use IsNothing(object)
Private Function EqualsNothing(ByVal item As Object) As Boolean
Return IsNothing(item)
End Function
Upvotes: 3