|
■No77483 (ミルク さん) に返信 > 下記の場合に上段は false, 下段はtrue になりますが、
既定では、C# の == 演算子は Object.ReferenceEquals(obj1, obj2) の意味で動作します。 すなわち、2 つの参照が同じオブジェクトを示すかどうかです。
しかし String 型のように、参照の一致性ではなく、 内容の一致性で比較するように実装されている型もあります。 (これが VB だと、さらに事情が変わってくるのですが)
> 文字列の場合 object での比較は正常に動作しているということなのでしょうか? 比較演算子の実装はオーバーロードされることがありますので、 何を持って「正常」とみなすかは、ケースバイケースだったりします。
> 数値の場合は直接メモリアドレスが割り当てられているから異なり 比較動作はそれぞれの型によりますので、 数値かどうか、値型か参照型か、といった話とは 分けて考えた方が良いかと思います。
たとえば、「違う型であっても、同じ内容を示していれば true とする」場合があります。 下記の例で言えば、o == p も x == y も true です。
char o = '1'; int p = 49;
DateTime x = new DateTime(2000, 1, 2, 3, 4, 5, 6, DateTimeKind.Utc); DateTimeOffset y = new DateTimeOffset(2000, 1, 2, 3, 4, 5, 6, TimeSpan.Zero);
また、下記のようなケースもあります。
decimal a = 10.00m; decimal b = 10.000m;
この場合、a == b は true を返します。 実際、同じ値として処理された方が都合が良いとは思いますが、 内部的には別のバイナリです。それぞれの有効桁数が異なりますね。
内部値を取り出してみると decimal.GetBits(a) は { 1000, 0, 0, 0x20000 } decimal.GetBits(b) は { 100, 0, 0, 0x10000 } という別のバイナリで表現されていますし、 既定の文字列化表現も a.ToString() ≠ b.ToString() です。
decimal のように、同じ型の別変数であっても、内容が同じなら一致とみなすケースもありますし、 int と long のように、違う型であっても、互換性がある値なら一致とみなすようにもできます。 もちろん、型の違いまでも含めて差異をチェックする実装もあるわけで。
> .Net の場合 同じ文字列は参照アドレス共通で使うようになっているとか > なんでしょうか? それに近い仕組みはあります。「文字列インターンプール」というやつですね。 ただし、本件はそれとはまた別の問題です。
文字列をリテラルで埋め込むのではなく、StringBuilder 経由で生成すれば 同じ文字列を異なるインスタンスとして生成できます。しかし、 参照先が異なる String インスタンスであったとしても、文字列の内容が 一致していれば、両者が同一視されるように実装されています。
StringBuilder sb = new StringBuilder("10"); string s1 = sb.ToString(); string s2 = sb.Append("").ToString();
// 別のインスタンスなので False Console.WriteLine(Object.ReferenceEquals(s1, s2));
// 内容はどちらも「10」なので True Console.WriteLine(s1 == s2);
|