以下のプログラムをコンパイルして実行した結果、どうなるでしょう。
struct Position {
public int x, y;
public void Print() {
Console.WriteLine(x.ToString() + "," + y.ToString());
}
public void swap() {
int tmp = x;
x = y;
y = tmp;
}
public Position(int x, int y) {
this.x = x;
this.y = y;
}
}
static void Main(string[] args) {
var poslist = new List<Position>();
poslist.Add(new Position(100, 200));
poslist[0].Print();
poslist[0].x += 300;
poslist[0].Print();
}
なんと、コンパイルできません。
"エラー CS1612: 変数ではないため、'System.Collections.Generic.List<strlist.Program.Position>.this[int]' の戻り値を変更できません。"
こんなエラーが出るんですね。
では、このように関数の内部で値を変更してはどうでしょう。
static void Main(string[] args) {
/* Positionの定義は上のソースと同じ */
var poslist = new List<Position>();
poslist.Add(new Position(100, 200));
poslist[0].Print();
poslist[0].swap();
poslist[0].Print();
}
今度はコンパイルはできますが、予想通りswap()での交換は行われていません。
問題はposlist[0]の部分ですね。
上で出たエラーから推測すると、poslist[0]はposlist[0]ではありません。
poslist[0]の内容がコピーされたものが帰ってきているわけです。
Listに入れているものがclassであれば、実体を指し示す位置なので
コピーされたものであっても問題がありません。
しかし、今回はstructですので、コピーされたものを更新してしまい、
実際のposlist[0]の中身はまったく更新されないわけですね。
poslist[0].xとかやると、それ更新しても意味ないよって事でしょう。
ということで、結論です。
- struct と Collections は相性が悪いので組み合わせないようにしましょう。
- 追跡参照…追跡参照さえあればこんなことには…!!
#List<int>はまずいの?という話になりそうなんですが、その辺はもうちょっと調べて書きます。