0

请参阅以下代码:

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通用,但这没有帮助。

4

4 回答 4

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 放入对象 i 会强制框,就像调用方法一样。

结果,如问题所示:

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,但对象可以,因此系统的行为是完全合适的。

同样,整数不能是空的。将它与 Nothing 进行比较几乎毫无意义——除了 CLR 类型系统有一个 Equals 必须返回某些东西的协定。

所以你应该做的是重新分析你正在做的事情,这样你就永远不会将纯整数与 Nothing 进行比较,也永远不会通过过程或函数的形式参数强制错误框。相反,将它们作为 Integer 按值传递,这样就不会发生装箱。


如果您绝对必须这样做,请进行两次重载。

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

再一次,它的late-- 语法没有被检查。这样做的风险是,如果对象不是整数,你会得到一个异常。

于 2012-11-23T01:06:50.593 回答
3

您可以使用 IsNothing(object) 而不是使用 Equals

Private Function EqualsNothing(ByVal item As Object) As Boolean
 Return IsNothing(item)     
End Function
于 2012-11-23T01:01:05.017 回答
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
于 2012-11-26T17:25:53.770 回答
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

这只是一个拆箱对象的问题,但可以扩展为支持您使用的任何类型。只是聪明点,把这个功能放在一个共享对象比较中,这样它就不会被复制粘贴到任何地方。

于 2012-11-23T11:28:00.817 回答