C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[14]: Object の比較についての疑問


(過去ログ 131 を表示中)

[トピック内 32 記事 (1 - 20 表示)]  << 0 | 1 >>

■77483 / inTopicNo.1)  Object の比較についての疑問
  
□投稿者/ ミルク (1回)-(2015/10/23(Fri) 15:43:53)

分類:[.NET 全般] 

C# .Net です

理解できないので、質問させていただきます。

下記の場合に上段は false, 下段はtrue になりますが、
文字列の場合 object での比較は正常に動作しているということなのでしょうか?

間違っていたらすみません。
数値の場合は直接メモリアドレスが割り当てられているから異なり
文字列は参照アドレスの比較が行われているから
.Net の場合 同じ文字列は参照アドレス共通で使うようになっているとか
なんでしょうか?

object obj1, obj2;

obj1 = 10;
obj2 = 10;
MessageBox.Show((obj1 == obj2).ToString());

obj1 = "10";
obj2 = "10";
MessageBox.Show((obj1 == obj2).ToString());
引用返信 編集キー/
■77485 / inTopicNo.2)  Re[1]: Object の比較についての疑問
□投稿者/ PANG2 (93回)-(2015/10/23(Fri) 16:15:30)
2015/10/23(Fri) 16:16:47 編集(投稿者)

削除
引用返信 編集キー/
■77486 / inTopicNo.3)  Re[2]: Object の比較についての疑問
□投稿者/ furu (26回)-(2015/10/23(Fri) 16:31:33)
obj1 == obj2の質問ですね。

数値と文字列どちらもobjectに代入されているので
参照アドレスの比較だと思います。

コンパイラの最適化で
たまたま文字列だけ同じ参照になったのではないでしょうか?

引用返信 編集キー/
■77487 / inTopicNo.4)  Re[1]: Object の比較についての疑問
□投稿者/ WebSurfer (681回)-(2015/10/23(Fri) 16:47:07)
No77483 (ミルク さん) に返信

以下の記事は説明になってないでしょうか?

== 演算子 (C# リファレンス)
https://msdn.microsoft.com/ja-jp/library/53k8ybth.aspx

> 数値の場合は直接メモリアドレスが割り当てられているから異なり

それについては以下の記事が参考になりませんか?

ボックス化とボックス化解除 (C# プログラミング ガイド)
https://msdn.microsoft.com/ja-jp/library/yz2be5wk.aspx
引用返信 編集キー/
■77488 / inTopicNo.5)  Re[3]: Object の比較についての疑問
□投稿者/ 774RR (330回)-(2015/10/23(Fri) 16:50:59)
前半はボクシングによって異オブジェクトになるので常に偽

後半はソースコード上の固定文字列が最適化によって1オブジェクトとなり
両者がそれ(同一ブツ)を指すので、コンパイラの仕様が大きく変わらない限り常に真

たまたま同じ内容の文字列、が勝手に同一オブジェクトになってしまう、ようなことはないので
obj2 = System.String.Format("{0}", 10);
とした場合は obj1 != obj2 になる。
引用返信 編集キー/
■77490 / inTopicNo.6)  Re[1]: Object の比較についての疑問
□投稿者/ 魔界の仮面弁士 (542回)-(2015/10/23(Fri) 17:37:51)
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);
引用返信 編集キー/
■77492 / inTopicNo.7)  Re[2]: Object の比較についての疑問
□投稿者/ furu (27回)-(2015/10/23(Fri) 20:02:58)
No77490 (魔界の仮面弁士 さん) に返信
> ■No77483 (ミルク さん) に返信
>>文字列の場合 object での比較は正常に動作しているということなのでしょうか?
> 比較演算子の実装はオーバーロードされることがありますので、
> 何を持って「正常」とみなすかは、ケースバイケースだったりします。

「object での比較」と書かれているので
オーバーロードは関係ないように思います。
引用返信 編集キー/
■77502 / inTopicNo.8)  Re[2]: Object の比較についての疑問
□投稿者/ なちゃ (86回)-(2015/10/26(Mon) 00:13:19)
今回の比較は両辺object型変数なので、あくまで参照の比較になります。
書かれている通り、文字列は実装上文字列プールの同一インスタンスの参照になるのでtrue、数値は個別にボックス化されるので、別のインスタンスとなりfalseです。
文字列リテラルの実際のインスタンスが実装上どのような割り当てになるかは結構複雑な動きだったような気がします。

引用返信 編集キー/
■77503 / inTopicNo.9)  Re[3]: Object の比較についての疑問
□投稿者/ ミルク (2回)-(2015/10/26(Mon) 09:40:27)
furu さんは たまたま同じになったと書かれていますが、
魔界の仮面弁士 さんは内容比較される(stringの場合)と書かれています。

たまたまというのは考えにくいので
やはり、string に関しては内容を参照し、
数値の場合は参照アドレスの比較が行われているということでいいのですよね。

と、なると
型によって処理が変えられているのはどうしてなのでしょう?
と疑問に思うのですが。



引用返信 編集キー/
■77504 / inTopicNo.10)  Re[4]: Object の比較についての疑問
□投稿者/ WebSurfer (683回)-(2015/10/26(Mon) 09:55:20)
No77503 (ミルク さん) に返信
> furu さんは たまたま同じになったと書かれていますが、
> 魔界の仮面弁士 さんは内容比較される(stringの場合)と書かれています。
>
> たまたまというのは考えにくいので
> やはり、string に関しては内容を参照し、
> 数値の場合は参照アドレスの比較が行われているということでいいのですよね。
>
> と、なると
> 型によって処理が変えられているのはどうしてなのでしょう?
> と疑問に思うのですが。

紹介した記事 ↓ を読みましたか? 無視? or 読んでも意味が分からない?

== 演算子 (C# リファレンス)
https://msdn.microsoft.com/ja-jp/library/53k8ybth.aspx

引用返信 編集キー/
■77506 / inTopicNo.11)  Re[4]: Object の比較についての疑問
□投稿者/ PANG2 (94回)-(2015/10/26(Mon) 10:25:52)
No77503 (ミルク さん) に返信
> furu さんは たまたま同じになったと書かれていますが、
> 魔界の仮面弁士 さんは内容比較される(stringの場合)と書かれています。

文字列を object型で比較した時は参照の比較であり、string型で比較した時は値の比較です。

// object型の比較
object obj1 = "10";
object obj2 = "10";
object obj3 = "1" + "0";
object obj4 = new string(new char[] { '1', '0' });
object obj5 = 10.ToString();

Debug.WriteLine(obj1 == obj2); //true
Debug.WriteLine(obj1 == obj3); //true
Debug.WriteLine(obj1 == obj4); //false
Debug.WriteLine(obj1 == obj5); //false

//string型の比較
string s1 = "10";
string s2 = "10";
string s3 = "1" + "0";
string s4 = new string(new char[] { '1', '0' });
string s5 = 10.ToString();
Debug.WriteLine(s1 == s2); //true
Debug.WriteLine(s1 == s3); //true
Debug.WriteLine(s1 == s4); //true
Debug.WriteLine(s1 == s5); //true
引用返信 編集キー/
■77508 / inTopicNo.12)  Re[5]: Object の比較についての疑問
□投稿者/ ミルク (3回)-(2015/10/26(Mon) 10:37:54)
No77504 (WebSurfer さん) に返信
>
> 紹介した記事 ↓ を読みましたか? 無視? or 読んでも意味が分からない?
>
> == 演算子 (C# リファレンス)
> https://msdn.microsoft.com/ja-jp/library/53k8ybth.aspx
>

もちろん、読みました。

int i = 10;
objecto o = i;

これをボックス化という。ということ以外読みとれませんでした。
これが比較の処理がどのように行われるかとの関係性については理解できませんでした。
すみません。



引用返信 編集キー/
■77509 / inTopicNo.13)  Re[5]: Object の比較についての疑問
□投稿者/ 774RR (331回)-(2015/10/26(Mon) 11:00:03)
ではこちらも読みましたか?(既に挙げられている URL)

ボックス化とボックス化解除 (C# プログラミング ガイド)
https://msdn.microsoft.com/ja-jp/library/yz2be5wk.aspx

Object の比較は「同一 new されたものか」になります。
(この際 String の比較は忘れなければならない)

boxing は数値型から参照型への代入が行われるたびに毎回暗黙に行われます。
Object o1=10; // boxing 発生 new が実行される
Object o2=10; // boxing 発生 new が実行される
o1 の指すオブジェクト (1回目の boxing の結果) と、
o2 の指すオブジェクト (2回目の boxing の結果) と、
両者は別オブジェクト (別に new されたもの) なので o1!=o2 です。

String は(不変オブジェクトの)参照型なので以下略 (No77506)

引用返信 編集キー/
■77510 / inTopicNo.14)  Re[5]: Object の比較についての疑問
□投稿者/ ミルク (4回)-(2015/10/26(Mon) 11:08:28)
No77506 (PANG2 さん) に返信
> 文字列を object型で比較した時は参照の比較であり、string型で比較した時は値の比較です。
>
> // object型の比較
> object obj1 = "10";
> object obj2 = "10";
> object obj3 = "1" + "0";
> object obj4 = new string(new char[] { '1', '0' });
> object obj5 = 10.ToString();
>
> Debug.WriteLine(obj1 == obj2); //true
> Debug.WriteLine(obj1 == obj3); //true
> Debug.WriteLine(obj1 == obj4); //false
> Debug.WriteLine(obj1 == obj5); //false
>

参照というのは参照アドレス値ということですよね。
値で比較するというのであれば、いずれもTrueになるのは理解できます。

obj1 と obj2 が同じ参照位置にあることが理解できません。
最初は、List<String>のように、同じ文字れつがあれば、Addせずに同じ参照値を設定し、
文字列が変わればAddするようなイメージを持っていましたが、
どうやらそうではなさそうですね。

引用返信 編集キー/
■77511 / inTopicNo.15)  Re[6]: Object の比較についての疑問
□投稿者/ Hongliang (362回)-(2015/10/26(Mon) 11:39:34)
> obj1 と obj2 が同じ参照位置にあることが理解できません。
ソースコードに直接記述されている文字列(リテラル文字列)は、コンパイル後のバイナリにもそのまま残ります。
.NETにおいてStringは不変オブジェクトという扱いであり、実行中に値が変わることはありません。
string a = "10";
としたとき、何かの操作によって"11"になったりはしないということです。

そのため、リテラル文字列"10"が複数の箇所で記述されているとき、それらをいちいちバイナリに出力すればexeファイルが無駄に太り、実行時にはそれらを別々にメモリにロードしてメモリを無駄食いし、となるだけで意味がないことになります。
ですので、同じ文字列を持ったリテラル文字列は、コンパイル時に一つの共通のStringインスタンスとしてまとめられます。

リテラル文字列でない、実行時に文字列が生成される物についても、(不変ではあるので)上記のように同じ物を一つのインスタンスにまとめることも技術的には可能ですが、文字列を生成する度に既存の文字列リストに一致する物があるか検索するコストなどを考えて採用されていません。
ですので同じ文字列でもそれぞれ異なるインスタンスの参照になります。
引用返信 編集キー/
■77512 / inTopicNo.16)  Re[6]: Object の比較についての疑問
□投稿者/ furu (28回)-(2015/10/26(Mon) 11:40:07)
No77510 (ミルク さん) に返信
> obj1 と obj2 が同じ参照位置にあることが理解できません。

文字列は非常に大きなメモリを必要とし、
なおかつ定数である場合が多いので
コンパイラの最適化で同じものは1個にすることは
かなりメモリの削減となります。

なおかつ、文字列は絶対に中身が変わらないので
値型のように別々にコーディングされた変数が同じ
参照を持っても問題がありません。

このため、"1" + "0"を"10"を同じ参照とするよう
コンパイラが頑張っています。

intのボックス化でも同じで、コンパイラの実装しだいで
同じ参照にしてもいいじゃないかと思いますが
そのような状況が少ないのとメモリの削減がそれほど
期待できないからか、(vs2010では)同じ参照にはなっていません。

ですので、定数、または、定数式の参照が同じ参照になるのは
「たまたま」と考えた方がいいんじゃないでしょうか?

私はそう思います。

それから==は、オーバーロードで、オーバーライドではないので
objectでの比較は、常に必ず参照の比較となります。

引用返信 編集キー/
■77513 / inTopicNo.17)  Re[6]: Object の比較についての疑問
□投稿者/ WebSurfer (685回)-(2015/10/26(Mon) 11:40:25)
No77508 (ミルク さん) に返信

== 以前のプリミティブな話ですが、値型と参照型の違いは理解してますか?
引用返信 編集キー/
■77514 / inTopicNo.18)  Re[7]: Object の比較についての疑問
□投稿者/ PATIO (3回)-(2015/10/26(Mon) 13:18:16)
2015/10/26(Mon) 13:34:44 編集(投稿者)
2015/10/26(Mon) 13:34:05 編集(投稿者)
2015/10/26(Mon) 13:32:47 編集(投稿者)
2015/10/26(Mon) 13:19:55 編集(投稿者)

>obj1 と obj2 が同じ参照位置にあることが理解できません。
皆さんが既にいろいろ解説されていますが、
一言で言うとobj1とobj2が指している物は「定数」だからです。
プログラム内の定数領域に格納されている"10"という文字列データです。
同じ内容の定数なら複数持つ意味はないので一つに纏められ、
プログラム内に"10"という定数は一つしない状態になります。
その為、obj1とobj2は同じ物を参照することになり、アドレスが同一になります。

newでstringを作成してその作成された物のアドレスを参照型に代入した場合は、
上記の定数を使っているわけではないので別のアドレスになります。
ToStringの返却値であるstringのインスタンスも新たに生成されます。

蛇足になりますが、
object型としての同じものとはどういう物かと考えた時に
中の値、例えば二つのインスタンスが共に1という値を持っていたとしてもインスタンスとして別のものであれば、別のものという判断をするという意味だと思います。
値としては同じでもobjectとしては別のものという意味合いです。
定数を参照している場合、コンパイラの機能で同じ定数は一つに纏められ、二つのobjectは純粋に同じ物を指した状態になります。
この為、この状態の二つのオブジェクトは厳密な意味で同じになります。

引用返信 編集キー/
■77515 / inTopicNo.19)  Re[8]: Object の比較についての疑問
□投稿者/ furu (29回)-(2015/10/26(Mon) 14:03:12)
No77514 (PATIO さん) に返信
> 一言で言うとobj1とobj2が指している物は「定数」だからです。

定数でなくても同じ参照になる場合がありますが
string.Emptyは特別待遇だからしょうがないか。

object obj1 = "";
object obj2 = string.Empty;
引用返信 編集キー/
■77520 / inTopicNo.20)  Re[7]: Object の比較についての疑問
 
□投稿者/ ミルク (5回)-(2015/10/27(Tue) 08:47:02)
No77513 (WebSurfer さん) に返信
> ■No77508 (ミルク さん) に返信
>
> == 以前のプリミティブな話ですが、値型と参照型の違いは理解してますか?

確実に理解しているかといわれると疑問ですけど

値型は変数が示す先にデータが保存されている。
参照型は変数が示す先にデータの保存領域が保存されているということぐらいです。




引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -