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

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

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

No.68597 の関連記事表示

<< 0 >>
■68597  なぜ結果が違うのでしょうか?
□投稿者/ 迷える小執事 -(2013/10/31(Thu) 13:20:53)

    分類:[.NET 全般] 

    L1とL2の内容が違うのはなぜでしょう?
    L1[0] と L2[0] が同じものを指していないから?
    でしょう・・

    object obj = new object();
    List<object> L1 = new List<object>();
    List<object> L2 = new List<object>();
    L1.Add(obj);
    L2.Add(L1[0]);
    L1[0] = "test";
    // L1=Test; L2=System.Object
    MessageBox.Show("L1=" + L1[0].ToString() + "; L2=" + L2[0].ToString());

    でも・・
    以下は同じ
    object obj = new object();
    obj = "Test";
    List<object> L1 = new List<object>();
    List<object> L2 = new List<object>();
    L1.Clear();
    L1.Add(obj);
    L2.Clear();
    L2.Add(L1[0]);
    // L1=Test; L2=Test
    MessageBox.Show("L1=" + L1[0].ToString() + "; L2=" + L2[0].ToString());

    理解できません。
    教えてください。
親記事 /過去ログ116より / 関連記事表示
削除チェック/

■68600  Re[1]: なぜ結果が違うのでしょうか?
□投稿者/ とっちゃん -(2013/10/31(Thu) 15:13:24)
>
    No68597 (迷える小執事 さん) に返信
    > L1とL2の内容が違うのはなぜでしょう?
    > L1[0] と L2[0] が同じものを指していないから?
    > でしょう・・
    >
    > object obj = new object();
    > List<object> L1 = new List<object>();
    > List<object> L2 = new List<object>();
    > L1.Add(obj);
    > L2.Add(L1[0]);
    > L1[0] = "test";
    > // L1=Test; L2=System.Object
    > MessageBox.Show("L1=" + L1[0].ToString() + "; L2=" + L2[0].ToString());
    >
    このコードの、
    L1[0] = "test";
    の手前でもMessageBox.Show() を表示してみてください。


    > でも・・
    > 以下は同じ
    > object obj = new object();
    > obj = "Test";
    > List<object> L1 = new List<object>();
    > List<object> L2 = new List<object>();
    > L1.Clear();
    > L1.Add(obj);
    > L2.Clear();
    > L2.Add(L1[0]);
    > // L1=Test; L2=Test
    > MessageBox.Show("L1=" + L1[0].ToString() + "; L2=" + L2[0].ToString());
    >
    こちらは、MessageBox.Show() のうしろに
    L1[0] = "test2";
    MessageBox.Show("L1=" + L1[0].ToString() + "; L2=" + L2[0].ToString());

    としてみてください。
    結果を見て、どう感じますか?
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68602  Re[2]: なぜ結果が違うのでしょうか?
□投稿者/ 迷える小執事 -(2013/10/31(Thu) 16:09:44)
    L1[0] は obj のコピー
    L2[0] は L1[0] のコピー
    つまり

    obj,L1[0],L2[0]
    それぞれ別ものってことですよね。


    では、obj も L1[0] も L2[0] も同じになるように(参照型)
    になるようにするにはどうすればいいのでしょうか?
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68603  Re[3]: なぜ結果が違うのでしょうか?
□投稿者/ とっちゃん -(2013/10/31(Thu) 16:53:35)
>
    No68602 (迷える小執事 さん) に返信
    > L1[0] は obj のコピー
    > L2[0] は L1[0] のコピー
    > つまり
    >
    > obj,L1[0],L2[0]
    > それぞれ別ものってことですよね。
    >
    ここでいうコピーとはなんでしょう?
    参照型でコピー(複製)という場合、何を複製しているのかが重要になります。

    > では、obj も L1[0] も L2[0] も同じになるように(参照型)
    > になるようにするにはどうすればいいのでしょうか?

    obj と L1[0], L2[0] が同じものを参照すれば同じになります。
    違うものを参照すれば、異なるものとなります。

    禅問答のように感じると思いますが、参照型とはそういうもの(ただしかなり乱暴な表現)なので。。。
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68609  Re[1]: なぜ結果が違うのでしょうか?
□投稿者/ 魔界の仮面弁士 -(2013/10/31(Thu) 21:43:02)
    2013/10/31(Thu) 21:50:22 編集(投稿者)

    No68597 (迷える小執事 さん) に返信
    > L1とL2の内容が違うのはなぜでしょう?

    //--------------
    int a = 123;
    int b = a;
    a = 456;
    MessageBox.Show(a.ToString()); // 変数 a の値は 123 から、456 に変更されている。
    MessageBox.Show(b.ToString()); // 変数 b の値は 123 のままであり、456 にはならない。

    上記は理解できますか?


    //--------------
    var a = this.textBox1;
    var b = a;
    a = this.textBox2;
    MessageBox.Show(a.Text); // 変数 a が参照するオブジェクトは、textBox1 から textBox2 に変更されている。
    MessageBox.Show(b.Text); // 変数 b が参照するオブジェクトは textBox1 のままであり、textBox2 にはなっていない。

    上記は理解できますか?


    //--------------
    var a = this.textBox1;
    var b = a;
    a = this.textBox2;
    a.Text = "xyz";
    MessageBox.Show(a.Text); // 変数 a が指す textBox2 に対して、Text が "xyz" に変更されている。
    MessageBox.Show(b.Text); // 変数 b が指す textBox1 の Text は書き換えられていない。

    上記は理解できますか?


    //--------------
    var L1 = new List<TextBox>();
    var L2 = new List<TextBox>();
    L1.Add(this.textBox1);
    L2.Add(L1[0]);
    L1[0] = this.textBox2;
    MessageBox.Show(L1[0].Text); // L1[0] が参照するオブジェクトは、textBox1 から textBox2 に変更されている。
    MessageBox.Show(L2[0].Text); // L2[0] が参照するオブジェクトは textBox1 のままであり、textBox2 にはなっていない。

    上記は理解できますか?
    元質問( No68597 )の前半部で行われている動作は、これに近いですね。


    //--------------
    var L1 = new List<TextBox>();
    var L2 = new List<TextBox>();
    L1.Add(this.textBox1);
    L2.Add(L1[0]);
    L1[0].Text = "xyz";
    MessageBox.Show(L1[0].Text); // L1[0] が指す textBox1 に対して、Text が "xyz" に変更されている。
    MessageBox.Show(L2[0].Text); // L2[0] も同じ textBox1 を参照しているため、Text は "xyz" と表示される。

    上記は理解できますか?


    //--------------
    var L1 = new List<TextBox>();
    var L2 = new List<TextBox>();
    L1.Add(this.textBox1);
    L2.Add(L1[0]);
    L1[0] = this.textBox2;
    L1[0].Text = "xyz";
    MessageBox.Show(L1[0].Text); // L1[0] が参照する textBox2 に対して、Text が "xyz" に変更されている。
    MessageBox.Show(L2[0].Text); // L2[0] が参照するオブジェクトは textBox1 のままなので、Text は変更されない。

    上記は理解できますか?
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68610  Re[2]: なぜ結果が違うのでしょうか?
□投稿者/ 魔界の仮面弁士 -(2013/10/31(Thu) 21:47:09)
    2013/10/31(Thu) 22:05:07 編集(投稿者)

    No68609 (魔界の仮面弁士) に追記
    > int a = 123;
    > int b = a;
    > a = 456;
    > MessageBox.Show(a.ToString()); // 変数 a の値は 123 から、456 に変更されている。
    > MessageBox.Show(b.ToString()); // 変数 b の値は 123 のままであり、456 にはならない。

    ついでに、値型と参照型の動作の違いについても。


    struct X { public int v; }
    class Y { public int v; }

    private void button1_Click(object sender, EventArgs e)
    {
      var a = new X() { v = 111 };
      var b = a;
      a.v = 222;
      MessageBox.Show(b.v.ToString()); // 111 のまま (X は値型なので)

      var c = new Y() { v = 333 };
      var d = c;
      c.v = 444;
      MessageBox.Show(c.v.ToString()); // 333 → 444 に変更 (Y は参照型なので)

      var obj = new X() { v = 555 };
      var refObject = __makeref(obj);
      __refvalue(refObject, X).v = 666;
      MessageBox.Show(obj.v.ToString()); // 555 → 666 に変更 (型付き参照を通じた変更…まず使わない)
    }
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68611  Re[2]: なぜ結果が違うのでしょうか?
□投稿者/ 迷える小執事 -(2013/11/01(Fri) 08:42:40)
    No68609 (魔界の仮面弁士 さん) に返信
    > 2013/10/31(Thu) 21:50:22 編集(投稿者)
    >
    > ■No68597 (迷える小執事 さん) に返信
    >>L1とL2の内容が違うのはなぜでしょう?
    >
    〜〜〜〜〜<<中略>>〜〜〜〜〜
    >
    > 上記は理解できますか?

    理解できているとおもいます。
    理解できないのは

    > var L1 = new List<TextBox>();
    > var L2 = new List<TextBox>();
    > L1.Add(this.textBox1);
    > L2.Add(L1[0]);
    > L1[0].Text = "xyz";
    > MessageBox.Show(L1[0].Text); // L1[0] が指す textBox1 に対して、Text が "xyz" に変更されている。
    > MessageBox.Show(L2[0].Text); // L2[0] も同じ textBox1 を参照しているため、Text は "xyz" と表示される。
    これなんですけど
    TextBoxではなくてObjectを使うとだめなのがわからないんです。

    object obj = new object();
    List<object> L1 = new List<object>();
    List<object> L2 = new List<object>();
    L1.Add(obj);
    L2.Add(L1[0]);
    obj = "xyz";
    MessageBox.Show(L1[0].ToString()); // L1[0] が指す obj "xyz" になる?
    MessageBox.Show(L2[0].ToString()); // L2[0] が指す L1[0] の指す obj の "xyz" になる?

    オブジェクトが理解できていない?
    オブジェクトってクラスじゃないのかな?
    それ以前の問題なのでしょうか?
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68613  Re[3]: なぜ結果が違うのでしょうか?
□投稿者/ 魔界の仮面弁士 -(2013/11/01(Fri) 09:39:47)
    No68611 (迷える小執事 さん) に返信
    > TextBoxではなくてObjectを使うとだめなのがわからないんです。

    型の問題では無いような。
    この使い方だと、List<object> でも List<TextBox> でも List<int> でも
    object obj; でも TextBox obj; でも int obj; でも同じ結果になるかと。


    > object obj = new object();
    「new object()」で生成された、object 型のインスタンス X を、
    object 型の変数 obj に代入しています。


    > List<object> L1 = new List<object>();
    > List<object> L2 = new List<object>();
    > L1.Add(obj);
    L1[0] には、そのインスタンス X が入ります。
    変数 obj をセットしているのではなく、変数 obj の中身をセットしているわけですね。


    > L2.Add(L1[0]);
    L2[0] にも、先のインスタンス X が入ります。
    変数 L1[0] の中身をセットしていますね。


    > obj = "xyz";
    「"xyz"」の文字列リテラルで生成された、string 型のインスタンス Y を、
    object 型の変数 obj に代入しています。この時点で、obj は X を見なくなります。


    > MessageBox.Show(L1[0].ToString()); // L1[0] が指す obj "xyz" になる?
    > MessageBox.Show(L2[0].ToString()); // L2[0] が指す L1[0] の指す obj の "xyz" になる?
    変数 obj の中身は、string 型のインスタンス Y に書き換えられましたが、
    変数 L1[0] の中身は、object 型のインスタンス X を指したままですし、
    変数 L2[0] の中身は、object 型のインスタンス X のままです。




    ===============================================================
    (1) string インスタンスの差し替え
    ---------------------------------------------------------------
    string obj = "bag";
    List<object> L1 = new List<object>();
    List<object> L2 = new List<object>();
    L1.Add(obj);
    L2.Add(L1[0]);
    obj = "bug"; // 変数 obj が参照しているインスタンスを差し替え
    MessageBox.Show(obj.ToString()); // string "bug" … 変更された
    MessageBox.Show(L1[0].ToString()); // string "bag" … そのまま
    MessageBox.Show(L2[0].ToString()); // string "bag" … そのまま


    ===============================================================
    (2) StringBuilder インスタンスの差し替え
    ---------------------------------------------------------------
    StringBuilder obj = new StringBuilder("bag");
    List<object> L1 = new List<object>();
    List<object> L2 = new List<object>();
    L1.Add(obj);
    L2.Add(L1[0]);
    obj = new StringBuilder("bug"); // 変数 obj が参照しているインスタンスを差し替え
    MessageBox.Show(obj.ToString()); // string "bug" … 変更された
    MessageBox.Show(L1[0].ToString()); // string "bag" … そのまま
    MessageBox.Show(L2[0].ToString()); // string "bag" … そのまま


    ===============================================================
    (3) インスタンスは差し替えず、参照先の内容のみを差し替え
    ---------------------------------------------------------------
    StringBuilder obj = new StringBuilder("bag");
    List<object> L1 = new List<object>();
    List<object> L2 = new List<object>();
    L1.Add(obj);
    L2.Add(L1[0]);
    obj[1] = 'u'; // StringBuilder そのものではなく、内容のみ変更
    MessageBox.Show(obj.ToString()); // string "bug" … 変更された
    MessageBox.Show(L1[0].ToString()); // string "bug" … 変更された
    MessageBox.Show(L2[0].ToString()); // string "bug" … 変更された
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68617  Re[4]: なぜ結果が違うのでしょうか?
□投稿者/ 魔界の仮面弁士 -(2013/11/01(Fri) 10:32:06)
    No68613 (魔界の仮面弁士) に追記
    >>> オブジェクトってクラスじゃないのかな?
    文脈次第で Yes にも No にも取れるので、厳密な線引きは難しいです。(^^;
    
    たとえば、C# では Int32 は class ではないですが、IL レベルで見れば Int32 も class ですし、
    VB.NET では、String は Object ですが、VB6 では String は Object ではなかったりして。
    
    
    とりあえず、
     「クラス(データ型)を、new 等で実体化(インスタンス化)したものを、オブジェクトと呼ぶ」
    という説明でどうでしょうか。
    
    
    
    >> 型の問題では無いような。
    >> この使い方だと、List<object> でも List<TextBox> でも List<int> でも
    >> object obj; でも TextBox obj; でも int obj; でも同じ結果になるかと。
    
    shu さんも書かれていますが、「インスタンスそのものを差し替える」のか、
    「インスタンスが指し示す内容を差し替える」のかの違いですね。
    
    
    ちなみに、string は参照型ですが、
     「内容が変化しない」
     「文字列リテラルで生成」
     「== 演算子は、参照一致(object.ReferenceEquals)ではなく、内容比較の意味」
    のような特性があるため、利用する側としては、値型のように扱われることになります。
    
    しかもリテラル文字列については、同じ文字列参照を流用することで
    メモリ使用量を抑えるようになっています。(文字列インターン プール)
    http://msdn.microsoft.com/ja-jp/library/system.string.intern.aspx
    http://msdn.microsoft.com/ja-jp/library/system.reflection.emit.opcodes.ldstr.aspx
    
    
    一応、string についても、インスタンスは差し替えずに中身だけ書き換える方法が
    存在しますが、アンセーフコードを使った特殊な書き方になってしまいます。
    
    unsafe private 
        void button1_Click(object sender, EventArgs e)
    {
        string obj = "bag";
        List<object> L1 = new List<object>();
        List<object> L2 = new List<object>();
        L1.Add(obj);
        L2.Add(L1[0]);
        fixed (char* c = obj) { *(c + 1) = 'u'; }
        MessageBox.Show(obj.ToString());    // string "bug" … 変更された
        MessageBox.Show(L1[0].ToString());  // string "bug" … 変更された
        MessageBox.Show(L2[0].ToString());  // string "bug" … 変更された
    }
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/

■68612  Re[3]: なぜ結果が違うのでしょうか?
□投稿者/ shu -(2013/11/01(Fri) 09:03:21)
    (迷える小執事 さん) に返信
    >>var L1 = new List<TextBox>();
    >>var L2 = new List<TextBox>();
    >>L1.Add(this.textBox1);
    >>L2.Add(L1[0]);
    >>L1[0].Text = "xyz";
    >>MessageBox.Show(L1[0].Text); // L1[0] が指す textBox1 に対して、Text が "xyz" に変更されている。
    >>MessageBox.Show(L2[0].Text); // L2[0] も同じ textBox1 を参照しているため、Text は "xyz" と表示される。
    > これなんですけど
    > TextBoxではなくてObjectを使うとだめなのがわからないんです。
    >
    L1[0].Textを書き換えているのであって最初に提示されたのと同じことを行うとすると
    L1[0] = this.textBox3
    のようになるわけでこれだとL1に入っているのはthis.textBox3でありL2に入っているのはthis.textBox1になるわけです。
    その点はobjectだからということではないです。
    objectだからということで言えばobjectだと定義されたプロパティとかがないのでTextプロパティへの設定のようなことが
    出来ないということです。
    つまりL1とL2に同じインスタンスをいれて片方の情報を書き換えたらもう片方の情報も書き換わるといったことをやりたいのであれば
    書き換える情報をもったクラスを作りインスタンスの置き換えにならないようにする必要があります。


    > L1[0] は obj のコピー
    > L2[0] は L1[0] のコピー
    > つまり
    >
    > obj,L1[0],L2[0]
    > それぞれ別ものってことですよね。
    この書き方だと最初から分かってましたと聞こえます。そうでなければ回答を貰ったことにより
    分かった旨を書くべきかと思います。
    そして、この全て別のものという解釈は間違ってます。
    L2[0]とobjは同じインスタンスです。L1[0]は"test"というインスタンスの代入によりobjとは別のものに変わります。
    objの内容を書き換えるのではなくL1[0]自体を書き換えているのです。
記事No.68597 のレス /過去ログ116より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -