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

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

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

List<T>の結果処理について

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

■93537 / inTopicNo.1)  List<T>の結果処理について
  
□投稿者/ ピカチュウ (2回)-(2019/12/19(Thu) 23:38:32)

分類:[C#] 

VS2008 ASP.netでやってますが、
C#の内容で質問しております

リストに追加・削除する前のリスト=listBefore、した後のリスト=listAfterで違いを比較して調べる処理を作っています。

本題ですが、listBeforeは4つ、listAfterは3つのリストにしたいと思っていますが、
下記の通りに処理すると、なぜかlistBeforeとlistAfterともに3つのリストになってしまいます。
どうしてこんな現象が起きるのでしょうか?

var getResult=〇〇//SQLで取ったList<class>のリスト。今回は4つのリストが入ってます

List<class> listBefore=new List<class>();
List<class> listAfter=new List<class>();

listBefore=getResult;
listAfter=getResult;

listAfter.removeat(1);
引用返信 編集キー/
■93538 / inTopicNo.2)  Re[1]: List<T>の結果処理について
□投稿者/ キングダム (52回)-(2019/12/20(Fri) 06:32:52)
No93537 (ピカチュウ さん) に返信

インスタンスが同じだからです

> var getResult=〇〇

getResult  ─ 〇〇

> List<class> listBefore=new List<class>();

getResult  ─ 〇〇
listBefore ─ new List<class>();

> List<class> listAfter=new List<class>();

getResult  ─ 〇〇
listBefore ─ new List<class>();
listAfter  ─ new List<class>();

> listBefore=getResult;

getResult  ┬ 〇〇
listBefore ┘
listAfter  ─ new List<class>();

> listAfter=getResult;

getResult  ┬ 〇〇
listBefore ┤
listAfter  ┘


引用返信 編集キー/
■93539 / inTopicNo.3)  Re[1]: List<T>の結果処理について
□投稿者/ sima (4回)-(2019/12/20(Fri) 06:48:07)
No93537 (ピカチュウ さん) に返信
> VS2008 ASP.netでやってますが、

VS2008 などという古いものをまだ使い続けるのはどうなのかなとは思いますが、
人様の環境はわからないのでもっと新しい Visual Studio に変えませんかとか余計なことは言いません。


実際の(あなたが動作させた)コードとデーターとで検証できないので、確かなことは
言えませんが、在り得る話として聞いてください。

listBefor が指しているインスタンスと、
listAfter が指しているインスタンスとが
同じものだからではないかと考えます。

listAfter には getResult から要素を取出して、新たなリストとして作り直したら
(要素になるインスタンスも当然同じ値の別のインスタンスにするのですよ)どうなりますか?
引用返信 編集キー/
■93540 / inTopicNo.4)  Re[1]: List<T>の結果処理について
□投稿者/ kiku (154回)-(2019/12/20(Fri) 09:30:09)
No93537 (ピカチュウ さん) に返信

simaさんが回答しているように、
同じインスタンスを参照していることが原因かと思います。

Listを別のインスタンスとしてコピーする方法は
下記が参考になると思います。

https://www.atmarkit.co.jp/ait/articles/1705/17/news017.html
https://www.atmarkit.co.jp/ait/articles/1705/24/news040.html

引用返信 編集キー/
■93542 / inTopicNo.5)  Re[1]: List<T>の結果処理について
□投稿者/ 魔界の仮面弁士 (2534回)-(2019/12/20(Fri) 10:58:15)
No93537 (ピカチュウ さん) に返信
> var getResult=〇〇//SQLで取ったList<class>のリスト。今回は4つのリストが入ってます

提示頂いたコードは、文法違反のエラーになりそうですね。

class という名前のクラスは作れませんし、メソッドについても
RemoveAt はあっても removeat はありませんので。


> どうしてこんな現象が起きるのでしょうか?

List<int> x = new List<int> { 10, 20, 30, 40 };
List<int> y = x;
List<int> z = x;
z.RemoveAt(0);

たとえば上記の場合、インスタンスは new List<int> ひとつだけです。
x や y や z が参照しているインスタンスは、同じものとなります。

そして RemoveAt は「インスタンス メソッド」です。

ひとつしか無いインスタンスを操作しているわけですから、
x、y、z いずれから見た場合も、その中身は
{ 10, 20, 30, 40 } から { 20, 30, 40 } に変化するというわけです。


もしもデータの複製が「シャローコピー」で構わない場合は、ToList を使う方法があります。

List<int> x = new List<int> { 10, 20, 30, 40 };
List<int> y = x.ToList();
List<int> z = x.ToList();
x[2] = 123;
y.RemoveAt(1);
z.RemoveAt(0);


.ToList() によって新しいインスタンスが生成されますので、
x、y、z が参照しているオブジェクトは、それぞれ別物となります。

x の中身は { 10, 20, 123, 40 } で、
y の中身は { 10, 30, 40 } で
z の中身は { 20, 30, 40 } ですね。



ただし「ディープコピー」が必要な場合は、ToList だけでは不足です。

List<int[]> x = new List<int[]> { new int[] { 10, 20 }, new int[] { 30, 40 } };
List<int[]> y = x.ToList();
List<int[]> z = x.ToList();
x[1][0] = 111;
y[0][0] = 222;
z[1] = new int[] { 123, 456 };

上記を実行すると、
x の中身は { { 222, 20 }, { 111, 40 } }
y の中身も { { 222, 20 }, { 111, 40 } }
z の中身は { { 222, 20 }, { 123, 456 } }
となります。

x,y,z はそれぞれ別のインスタンスですが、
x[0], y[0], z[0] が参照している配列は同一のインスタンスだからです。



上記を、kiku さんが紹介されていた記事にある DeepClone の実装に置き換えてみます。

List<int[]> x = new List<int[]> { new int[] { 10, 20 }, new int[] { 30, 40 } };
List<int[]> y = x.DeepClone();
List<int[]> z = x.DeepClone();
x[1][0] = 111;
y[0][0] = 222;
z[1] = new int[] { 123, 456 };

この場合、上記を実行した結果が
x の中身は { { 10, 20 }, { 111, 40 } }
y の中身も { { 222, 20 }, { 30, 40 } }
z の中身は { { 10, 20 }, { 123, 456 } }
となりますので、求めるものに近いのではないでしょうか?

なお、DeepClone メソッド内では Serialize / Deserialize メソッドが
利用されていますので、これが使えるのは、List<T> の T 型が
シリアル化可能な型である場合に限られます。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ