装箱后,等于(......)不会返回相同的值

Rud*_*dey 0 .net vb.net comparison equals value-type

请参阅以下代码:

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
Run Code Online (Sandbox Code Playgroud)

如何Equals在拳击结构后避免返回不同的东西?有没有办法调用原始Equals实现?

我知道=在这种情况下我可以使用运算符,但是EqualsNothing应该同时使用类和结构.该=运营商将不会VB.NET带班工作,也不会与没有执行这个操作结构的工作.Equals 确实适用于所有事情,但正如我在上面演示的那样,Equals拳击后不会返回相同的东西.

那么,我应该如何重写EqualsNothing以使其适用于类和结构?

编辑:我尝试制作EqualsNothing通用,但这没有帮助.

SAJ*_*SAJ 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())
Run Code Online (Sandbox Code Playgroud)

将0放在对象中i强制该框,就像调用方法一样.

结果如问题所示:

a=True
b=False
Run Code Online (Sandbox Code Playgroud)

产生的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         
Run Code Online (Sandbox Code Playgroud)

如您所见,区别在于调用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
Run Code Online (Sandbox Code Playgroud)

CLR语义将优先选择非盒装整数.

我是在凌晨3点写的,所以不检查上面的VB语法细节,因为这是对评论讨论的回应.

或者只是强制将事物取消装箱:

Private Function EqualsNothing(ByVal item As Object) As Boolean

   Dim int As Integer = item

   Return int.Equals(Nothing)
End Function
Run Code Online (Sandbox Code Playgroud)

再次,它的晚期语法没有检查.这样做的风险是,如果对象不是整数,则会出现异常.