请参阅以下代码:
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
如何在拳击结构后避免Equals
返回不同的东西?有没有办法调用原始Equals
实现?
我知道在这种情况下我可以使用=
运算符,但EqualsNothing
应该适用于类和结构。 =
运算符不能用于VB.NET中的类,并且它也不适用于没有实现此运算符的结构。 Equals
可以使用所有内容,但正如我在上面演示的那样,Equals
在装箱后不会返回相同的内容。
那么,我应该如何重写EqualsNothing
以便它适用于类和结构?
修改:我尝试将EqualsNothing
设为通用,但这没有帮助。
答案 0 :(得分:5)
我通常是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())
在对象中放置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结构)。这是一个价值对等检查。
在第二个实例中,调用Object.Equals进行引用比较 - 引用是否指向同一个对象?
您不应期望这些方法具有相同的行为。
我建议您自问为什么要将整数与Nothing进行比较?它们永远不会是虚无,但对象可以,所以系统的行为是完全合适的。
同样,整数也不可能是什么。将它与Nothing进行比较几乎没有意义 - 除了CLR类型系统有一个Equals必须返回的合同。
所以你应该做的是重新分析你正在做的事情,这样你就永远不会将普通整数与Nothing进行比较,也绝不会通过程序或函数的形式参数强制使用假框。相反,按值将它们作为整数传递,这样就不会发生拳击。
如果你绝对必须这样做,那就有两个重载。
Private Function EqualsNothing(ByVal item As Integer) As Boolean
Private Function EqualsNothing(ByVal item As Object) As Boolean
CLR语义将优先选择非盒装整数。
我是在凌晨3点写的,所以不要检查上面的VB语法细节,因为这是对评论讨论的回应。
或者只是强制取消装箱:
Private Function EqualsNothing(ByVal item As Object) As Boolean
Dim int As Integer = item
Return int.Equals(Nothing)
End Function
同样,它的晚期语法没有被检查。这样做的风险在于,如果对象不是整数,则会出现异常。
答案 1 :(得分:3)
您可以使用IsNothing(object)
,而不是使用EqualsPrivate Function EqualsNothing(ByVal item As Object) As Boolean
Return IsNothing(item)
End Function
答案 2 :(得分:1)
我不确定这会在所有情况下都有效,但您可以尝试这种通用方法:
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
答案 3 :(得分:0)
使用类型对象的魔力对你有利。
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
这只是解除对象的问题,但可以扩展为支持您使用的任何类型。只要聪明一点,将这个功能放在一个共享的对象比较中,这样它就不会粘贴在任何地方。