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元の実装を呼び出す方法はありますか?

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.

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())

オブジェクト i に 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 構造体) が呼び出されます。これは値の等価性チェックです。

2 番目のインスタンスでは、参照比較を行う Object.Equals が呼び出されます。参照は同じオブジェクトを指していますか?

これらのメソッドから同じ動作を期待するべきではありません。

なぜ整数を Nothing と比較するのかを自問する必要があることをお勧めします。それらは決してNothingになることはできませんが、オブジェクトはできるため、システムの動作は完全に適切です。

繰り返しますが、Integer を Nothing にすることはできません。それを Nothing と比較してもほとんど意味がありません。ただし、CLR 型システムには、Equals が何かを返さなければならないというコントラクトがあることを除きます。

したがって、何をしているのかを再分析して、単純な整数を Nothing と比較したり、プロシージャまたは関数の仮パラメータによって false ボックスを強制したりしないようにする必要があります。代わりに、ボックス化が起こらないように値で整数として渡します。


絶対にこれを行う必要がある場合は、2 つのオーバーロードを用意してください。

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

繰り返しますが、遅い構文はチェックされていません。これに伴うリスクは、オブジェクトが整数でない場合に例外が発生することです。

于 2012-11-23T01:06:50.593 に答える
3

Equals を使用する代わりに、IsNothing(object) を使用できます。

Private Function EqualsNothing(ByVal item As Object) As Boolean
 Return IsNothing(item)     
End Function
于 2012-11-23T01:01:05.017 に答える
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 に答える