C#のListと配列とオブジェクトのコピー

C# コンピュータ
C#

配列の要素を追加したい処理がありまして、ちょっと確認してみました。

C#の配列は基本的に要素数が固定の昔ながらの普通の配列です。ということで配列に要素を追加する場合、新たに大きな配列を用意し、その配列に要素をコピーする処理が必要になります。(ほかに方法があったらすみません)

今日のコンピュータでプログラミングの処理効率を考えるのは、私ごときが考えることでは無いと思いますが、さすがにこれは非効率です。多分配列のResize命令がそれにあたると思いますが、要素を一つ末尾に追加するのにResize処理を記述するとぱっと見て何をしているか理解に苦しむコードになりそうです。

個人的には「配列.Add(値)」とか「配列 += 値」ぐらいで要素の追加をしてくれると理解しやすいです。

そうなるとListの出番になるわけですが、個人的にジェネリックやテンプレートは難しいから嫌いなことはおいておくとしても、おおむね自分の希望に叶うふるまいをしてくれます。

Listですと添え字で各要素にアクセスできる点は配列と同等ですし、実際効率が良いかは不明ですがAddメソッドで要素を追加することが出来ます。

ですが、あくまでこれはListであって配列では無いです。.NetのAPIでは配列を引数に要求するメソッドが多数存在します。

C#のためだけに.NetのAPIが存在するわけでは無いのでList型を受け入れてくれないのは仕方がないのかもしれません。

そういう状況でListを使う場合、配列に変換する必要が出てきます。.ToArray()メソッドです。

これで配列に変換してあげればAPIを実行することできます。

ここで気になるは.ToArray()で変換された配列と元となるListは別である点です。これは当然なのですが、そこに含まれる要素は値であったりクラスののインスタンスあったりするわけですが、これもコピーされた別なオブジェクトであるかどうかという点です。

シンプルな数値や文字列などはコピーであってもあまり問題はないですが、複雑なクラスのインスタンスなどはコピーされると都合が悪いケースがあります。

オブジェクトが同一であるか確認するメソッドや比較演算子もあると思いますが、確認用のプログラムを組んでみます。

using System;
using System.Drawing;
using System.Collections.Generic;
using System.Windows.Forms;

/*
 配列とList<T>
*/

class Program
{
    static void Main()
    {
		// 数値
		List<int> intList = new List<int>{ 1, 2, 3};
		
		// 配列に変換
		var intListToArray = intList.ToArray();
		
		// 配列の要素を書き換える
		intListToArray[1] = 100;
		
		// リストの要素は変わっているか
		Console.WriteLine("{0}", intList[1]);
		// 2 変わっていない。ということはコピー
		
		
		// Point構造体
		
		// リスト
		List<Point> pointList = new List<Point>{
			new Point(0, 0),
			new Point(100, 100),
			new Point(150,50)
		};		
		// リストに要素を追加
		pointList.Add(new Point(30, 30));		
		
		// 配列に変換
		var pointListToArray = pointList.ToArray();
		
		// 配列の要素を書き換える
		pointListToArray[0].X = 100;
		
		// リストの要素は変わっているか
		Console.WriteLine("{0}", pointList[0].X);
		// 0 変わっていない。ということはコピー
		
		// Textboxコントロール(クラス)
		List<TextBox> txtboxList = new List<TextBox>{
			new TextBox() { Text = "A" },
			new TextBox() { Text = "B" },
			new TextBox() { Text = "C" }
		};
		
		// 配列に変換
		var txtboxListToArray = txtboxList.ToArray();
		
		// 配列の要素を書き換える
		txtboxListToArray[1].Text = "X";
		
		// リストの要素は変わっているか
		Console.WriteLine("{0}", txtboxList[1].Text);
		// X 変わっている。ということは参照
		
		
	}
}

数値や構造体などはコピーされるようです。オブジェクト(クラスのインスタンス)は参照されているようです。
個人的に都合の良いふるまいで安心しましたが、構造体が参照ではなくコピーなのが意外でした。構造体は機能的にはクラスに近いと思うのでクラスと同じ振る舞いをするのではと考えていました。同じnewで生成されるとしても構造体とクラスは別であることを覚えておけば取り合えず支障はなさそうです。

コメント