このコードがtrueを返すのはなぜですか。
new Byte() == new Byte() // returns true
しかし、このコードはfalseを返します:
new Byte[0] == new Byte[0] // returns false
new Byte()
は値タイプを作成し、値によって比較されるためです(デフォルトでは、値0
でbyte
が返されます)。そして、new Byte[0]
は、参照型であり、参照によって比較される配列を作成します(そして、配列のこれら2つのインスタンスは異なる参照を持ちます)。
詳細については、 値型と参照型 の記事を参照してください。
バイトは.NETでは 値型 です。つまり、2つのバイトの値が同じである場合に限り、==
演算子はtrueを返します。これは、 値の同等性 とも呼ばれます。
ただし、配列は.NETでは 参照型 です。つまり、==
演算子は、メモリ内の同じ配列インスタンスを参照する場合にのみtrueを返します。これは、 参照の同等性またはアイデンティティとも呼ばれます-) 。
==
演算子は、参照型と値型の両方でオーバーロードされる可能性があることに注意してください。たとえば、System.String
は参照型ですが、文字列の==
演算子は、配列内の各文字を順番に比較します。 Equals()および演算子のオーバーロードに関するガイドライン==(C#プログラミングガイド) を参照してください。
配列にがまったく同じ値(順番に)含まれているかどうかをテストする場合は、 Enumerable.SequenceEqual
==
の代わりに。
参照の比較とは、実際にはポインタアドレスを比較することです。これは、falseを返す理由であり、値アドレスでは、値を比較する必要はありません。
コンパイラは値型をレジスタに格納しようとしますが、レジスタ数が限られているため、参照型がスタックにあるが値がヒープ内のメモリアドレスのアドレスを保持している間、値がスタックにさらに格納されます [Reference] .
ここでの比較では、スタックに存在する値を比較します。最初のケースでは両方が同じですが、2番目のケースではヒープのアドレスが異なります。
両方のオペランドがタイプbyte
である==
演算子のオーバーロードがあり、各バイトの値を比較するために実装されています。この場合、2つのゼロバイトがあり、それらは等しいです。
==
演算子は配列に対してオーバーロードされないため、2番目のケースでは2つのobject
オペランドを持つオーバーロードが使用され(配列はタイプobject
であるため)、その実装は比較されます。 2つのオブジェクトへの参照。 2つの配列への参照は異なります。
これは、byte
が値型であり、配列が参照型であるという事実とは(直接)関係がないことに注意してください。 byte
の==
演算子には、値のセマンティクスがありますのみその実装では演算子の特定のオーバーロードがあるためです。そのオーバーロードが存在しなかった場合、be 2バイトが有効なオペランドとなるオーバーロードがないため、コードまったくコンパイルされませんになります。これは、カスタムstruct
を作成し、その2つのインスタンスを==
operatorと比較することで簡単に確認できます。これらのタイプに==
の独自の実装を提供しない限り、コードはコンパイルされません。