C#のnew Listとは?作成・初期化・値の追加まで初心者向けにわかりやすく解説

はじめに

C#で複数の値をまとめて扱いたいときによく使われるのが、List<T>です。List<T>を利用すると、要素を後から追加したり、不要な要素を削除したりできるため、要素数が変化するデータの管理に適しています。

C#を学び始めたばかりの方は、次のようなコードを見て「new Listとは何をしているのか」「List<int>intにはどのような意味があるのか」と疑問に感じるかもしれません。

C#
List<int> numbers = new List<int>();

このコードでは、整数を格納できる新しいリストを作成しています。

本記事では、C#のnew Listの基本的な意味から、リストの作成・初期化・値の追加・取得・削除までを、サンプルコードを使って初心者向けに解説します。よくあるエラーや配列との違いについても確認していきましょう。

1. C#のnew Listとは

1-1. Listは複数の値をまとめて管理できるコレクション

C#のList<T>は、複数の値を順番にまとめて管理できるコレクションです。

たとえば、3人分の名前を個別の変数で管理すると、次のようになります。

C#
string name1 = "田中";
string name2 = "佐藤";
string name3 = "鈴木";

人数が増えるたびに変数を追加しなければならないため、データが多くなると管理が難しくなります。

List<string>を使用すれば、複数の名前を1つの変数にまとめられます。

C#
List<string> names = new List<string>();

names.Add("田中");
names.Add("佐藤");
names.Add("鈴木");

List<T>には、主に次の特徴があります。

  • 複数の値を順番に格納できる

  • 作成後に要素を追加できる

  • 不要な要素を削除できる

  • インデックスを使って要素を取得できる

  • 格納できるデータ型を指定できる

配列も複数の値を管理できますが、基本的に作成時に要素数を決める必要があります。一方、List<T>は必要に応じて要素数を増減できるため、件数が変わるデータに向いています。

1-2. new Listでリストのインスタンスを作成する仕組み

C#のnewは、クラスから実際に使用できるオブジェクト、つまりインスタンスを作成するためのキーワードです。

次のコードでは、List<int>の新しいインスタンスを作成し、numbers変数に代入しています。

C#
List<int> numbers = new List<int>();

それぞれの部分には、次のような意味があります。

C#
List<int> numbers = new List<int>();
// 型 変数名 インスタンスの作成

左側のList<int>は変数の型、numbersは変数名です。右側のnew List<int>()が、新しいリストを作成する処理です。

new List<int>()によって作成された直後のリストには、要素が1つも入っていません。

C#
List<int> numbers = new List<int>();

Console.WriteLine(numbers.Count); // 0

このように、リストを利用するときは、基本的にnew List<T>()でインスタンスを作成してから値を追加します。

1-3. Listを使うために必要なusing System.Collections.Generic

List<T>は、System.Collections.Generic名前空間に定義されています。

そのため、C#ファイルの先頭で次のusingディレクティブを記述するのが一般的です。

C#
using System.Collections.Generic;

使用例は次のとおりです。

C#
using System;
using System.Collections.Generic;

class Program
{
static void Main()
{
List<string> names = new List<string>();
names.Add("田中");

Console.WriteLine(names[0]);
}
}

using System.Collections.Generic;を記述しない場合でも、完全修飾名を使えばList<T>を作成できます。

C#
System.Collections.Generic.List<int> numbers =
new System.Collections.Generic.List<int>();

ただし、コードが長くなるため、通常はusing System.Collections.Generic;を記述します。

新しい.NETプロジェクトでは、暗黙的なusingが有効になっており、自分で記述しなくてもList<T>を使用できる場合があります。それでも、List<T>System.Collections.Genericに属していることは覚えておきましょう。

1-4. List<T>のTに指定するデータ型とは

List<T>Tは、リストに格納する要素のデータ型を表します。Tは「Type」の意味で使われる一般的な表記です。

整数を格納する場合は、List<int>を使用します。

C#
List<int> numbers = new List<int>();

文字列を格納する場合は、List<string>を使用します。

C#
List<string> names = new List<string>();

小数を格納する場合は、List<double>を使用できます。

C#
List<double> prices = new List<double>();

自分で定義したクラスも指定できます。

C#
List<Product> products = new List<Product>();

List<int>には基本的にint型の値だけを追加できます。

C#
List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);
// numbers.Add("30"); // コンパイルエラー

追加できる型が決まっているため、間違った型のデータが混ざるのを防げることがList<T>の利点です。

2. new Listの基本的な作成方法

2-1. 空のListを作成する基本構文

空のリストを作成する基本構文は、次のとおりです。

C#
List<データ型> 変数名 = new List<データ型>();

文字列を格納する空のリストを作成する場合は、次のように記述します。

C#
List<string> names = new List<string>();

作成直後は、要素数が0です。

C#
Console.WriteLine(names.Count); // 0

空のリストは、後からAddメソッドなどを使って値を追加できます。

C#
names.Add("田中");
names.Add("佐藤");

2-2. int型のListを作成する方法

整数を格納するリストを作成する場合は、型引数にintを指定します。

C#
List<int> numbers = new List<int>();

作成したリストには、整数を追加できます。

C#
numbers.Add(10);
numbers.Add(20);
numbers.Add(30);

全体のコードは次のとおりです。

C#
using System;
using System.Collections.Generic;

class Program
{
static void Main()
{
List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);
numbers.Add(30);

foreach (int number in numbers)
{
Console.WriteLine(number);
}
}
}

実行結果は次のようになります。

10
20
30

2-3. string型のListを作成する方法

文字列を格納するリストを作成する場合は、List<string>を使用します。

C#
List<string> fruits = new List<string>();

文字列は、ダブルクォーテーションで囲んで追加します。

C#
fruits.Add("りんご");
fruits.Add("バナナ");
fruits.Add("みかん");

インデックスを指定すれば、特定の要素を取得できます。

C#
Console.WriteLine(fruits[0]); // りんご
Console.WriteLine(fruits[1]); // バナナ

インデックスは0から始まるため、最初の要素はfruits[0]です。

2-4. varを使ってListを作成する方法

右辺から変数の型を判断できる場合は、varを使ってリストを作成できます。

C#
var numbers = new List<int>();

この場合、numbersの型はList<int>です。varを使用しても、好きな型の値を追加できるようになるわけではありません。

C#
var numbers = new List<int>();

numbers.Add(10);
// numbers.Add("20"); // コンパイルエラー

varは型を省略しているのではなく、コンパイラに型を推論させる記述です。変数の型はコンパイル時に確定します。

値を指定して作成することもできます。

C#
var names = new List<string>
{
"田中",
"佐藤",
"鈴木"
};

型が明確でコードが読みやすくなる場合は、varを使用するとよいでしょう。

2-5. オブジェクトを格納するListを作成する方法

List<T>には、数値や文字列だけでなく、自分で作成したクラスのオブジェクトも格納できます。

たとえば、商品を表すProductクラスを定義します。

C#
class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Price { get; set; }
}

Productオブジェクトを格納するリストは、次のように作成します。

C#
List<Product> products = new List<Product>();

商品を追加する場合は、Productのインスタンスを作成してAddメソッドに渡します。

C#
Product product = new Product
{
Id = 1,
Name = "ノート",
Price = 300
};

products.Add(product);

インスタンスの作成と追加を同時に記述することもできます。

C#
products.Add(new Product
{
Id = 2,
Name = "ペン",
Price = 120
});

実際のアプリケーションでは、商品、ユーザー、注文などのデータをList<T>で管理する場面が多くあります。

3. new Listを初期化する方法

3-1. コレクション初期化子で値を設定する方法

リストの作成と同時に値を設定する場合は、コレクション初期化子を使用できます。

C#
List<int> numbers = new List<int>
{
10,
20,
30
};

1行で記述することも可能です。

C#
List<int> numbers = new List<int> { 10, 20, 30 };

文字列のリストも同様に初期化できます。

C#
List<string> colors = new List<string>
{
"赤",
"青",
"緑"
};

コレクション初期化子は、内部的には各要素に対してAddメソッドを呼び出す形で処理されます。

最初から登録する値が決まっている場合は、空のリストを作ってから1件ずつ追加するより、コレクション初期化子を使ったほうが簡潔です。

3-2. 配列からListを初期化する方法

List<T>のコンストラクターに配列を渡すと、配列の要素を持つ新しいリストを作成できます。

C#
int[] numberArray = { 10, 20, 30 };

List<int> numbers = new List<int>(numberArray);

作成されたnumbersには、102030が格納されています。

C#
foreach (int number in numbers)
{
Console.WriteLine(number);
}

文字列の配列からも作成できます。

C#
string[] nameArray = { "田中", "佐藤", "鈴木" };

List<string> names = new List<string>(nameArray);

配列をリストに変換すると、作成後に要素を追加したり削除したりしやすくなります。

C#
names.Add("高橋");
names.Remove("佐藤");

LINQを使用できる環境では、ToListメソッドで変換する方法もあります。

C#
using System.Linq;

int[] numberArray = { 10, 20, 30 };
List<int> numbers = numberArray.ToList();

3-3. 既存のListから新しいListを作成する方法

既存のリストをコンストラクターに渡すと、同じ要素を持つ新しいリストを作成できます。

C#
List<int> original = new List<int> { 10, 20, 30 };
List<int> copied = new List<int>(original);

この場合、originalcopiedは別のリストです。

C#
copied.Add(40);

Console.WriteLine(original.Count); // 3
Console.WriteLine(copied.Count); // 4

copiedに要素を追加しても、originalの要素数は変わりません。

ただし、クラスのオブジェクトを格納している場合、複製されるのはオブジェクトへの参照です。リスト自体は別でも、各要素が同じオブジェクトを参照する「浅いコピー」になる点に注意が必要です。

C#
List<Product> original = new List<Product>
{
new Product { Id = 1, Name = "ノート", Price = 300 }
};

List<Product> copied = new List<Product>(original);

copied[0].Price = 500;

Console.WriteLine(original[0].Price); // 500

要素となるオブジェクトまで完全に分けたい場合は、各オブジェクトを新しく作成してコピーする必要があります。

3-4. 要素数の目安をCapacityで指定して作成する方法

リストに追加する要素数の目安が分かっている場合は、コンストラクターで初期容量を指定できます。

C#
List<int> numbers = new List<int>(100);

このコードは、100件分の要素がすでに格納されているという意味ではありません。要素を格納するための領域を、あらかじめ100件分確保するという意味です。

C#
List<int> numbers = new List<int>(100);

Console.WriteLine(numbers.Count); // 0
Console.WriteLine(numbers.Capacity); // 100

Countは実際に格納されている要素数、Capacityは再確保せずに格納できる要素数を表します。

リストは容量が不足すると、より大きな内部領域を確保して要素を移し替えます。大量のデータを追加することが事前に分かっている場合は、適切な初期容量を指定することで、領域の再確保を減らせる可能性があります。

通常の小規模な処理では、容量を細かく意識せず、次の基本形で問題ありません。

C#
List<int> numbers = new List<int>();

3-5. 空のListとnullの違い

空のリストとnullは異なります。

空のリストは、リストのインスタンスは存在しているものの、要素が1件も格納されていない状態です。

C#
List<int> numbers = new List<int>();

Console.WriteLine(numbers.Count); // 0

空のリストには、Addメソッドで値を追加できます。

C#
numbers.Add(10);

一方、nullはリストのインスタンスが存在していない状態です。

C#
List<int>? numbers = null;

nullの変数に対してAddメソッドを呼び出すと、NullReferenceExceptionが発生します。

C#
List<int>? numbers = null;

// numbers.Add(10); // NullReferenceException

要素がない状態を表したいだけであれば、できるだけ空のリストを使用すると安全です。

C#
List<int> numbers = new List<int>();

nullの可能性がある場合は、事前に確認します。

C#
if (numbers != null)
{
numbers.Add(10);
}

または、null合体代入演算子を使って、nullの場合だけリストを作成できます。

C#
numbers ??= new List<int>();
numbers.Add(10);

4. new Listに値を追加する方法

4-1. Addメソッドで値を1件追加する方法

リストに値を1件追加するときは、Addメソッドを使用します。

C#
List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);
numbers.Add(30);

追加した値は、リストの末尾に入ります。

C#
Console.WriteLine(numbers[0]); // 10
Console.WriteLine(numbers[1]); // 20
Console.WriteLine(numbers[2]); // 30

文字列の場合も同様です。

C#
List<string> names = new List<string>();

names.Add("田中");
names.Add("佐藤");

Addメソッドの引数には、リストで指定した型の値を渡します。

4-2. AddRangeメソッドで複数の値をまとめて追加する方法

複数の値をまとめて追加したい場合は、AddRangeメソッドを使用します。

C#
List<int> numbers = new List<int> { 10, 20 };

numbers.AddRange(new int[] { 30, 40, 50 });

実行後のnumbersには、次の値が格納されます。

10, 20, 30, 40, 50

別のリストの要素を追加することもできます。

C#
List<string> names = new List<string>
{
"田中",
"佐藤"
};

List<string> additionalNames = new List<string>
{
"鈴木",
"高橋"
};

names.AddRange(additionalNames);

Addは1件の要素を追加し、AddRangeは配列やリストなどから複数の要素を追加します。

C#
numbers.Add(60);                       // 1件追加
numbers.AddRange(new[] { 70, 80 }); // 複数件追加

4-3. Insertメソッドで指定した位置に値を追加する方法

リストの途中に値を追加したい場合は、Insertメソッドを使用します。

C#
List<string> names = new List<string>
{
"田中",
"鈴木"
};

names.Insert(1, "佐藤");

第1引数には挿入位置のインデックス、第2引数には追加する値を指定します。

実行後の要素は次の順番になります。

田中
佐藤
鈴木

先頭に追加する場合は、インデックスに0を指定します。

C#
names.Insert(0, "高橋");

末尾に追加するだけであれば、通常はAddメソッドのほうが分かりやすいでしょう。

なお、0未満の値や、Countを超えるインデックスを指定すると、ArgumentOutOfRangeExceptionが発生します。末尾への挿入ではCountと同じ値を指定できます。

C#
names.Insert(names.Count, "山田");

4-4. 条件に応じてListへ値を追加する方法

if文とAddメソッドを組み合わせれば、条件を満たす値だけをリストに追加できます。

C#
List<int> evenNumbers = new List<int>();

for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
evenNumbers.Add(i);
}
}

このコードでは、1から10までの数値のうち、偶数だけが追加されます。

2, 4, 6, 8, 10

同じ値を重複して追加したくない場合は、Containsメソッドで確認できます。

C#
List<string> names = new List<string>();

string newName = "田中";

if (!names.Contains(newName))
{
names.Add(newName);
}

ただし、大量のデータに対して重複確認を頻繁に行う場合は、List<T>よりもHashSet<T>が適していることがあります。

4-5. オブジェクトのListにデータを追加する方法

オブジェクトを格納するリストにも、Addメソッドを使用できます。

C#
class User
{
public int Id { get; set; }
public string Name { get; set; } = "";
}

User型のリストを作成し、ユーザーを追加します。

C#
List<User> users = new List<User>();

users.Add(new User
{
Id = 1,
Name = "田中"
});

users.Add(new User
{
Id = 2,
Name = "佐藤"
});

コレクション初期化子を使用すれば、リストの作成とデータの追加をまとめて記述できます。

C#
List<User> users = new List<User>
{
new User
{
Id = 1,
Name = "田中"
},
new User
{
Id = 2,
Name = "佐藤"
}
};

登録したデータは、foreach文などで取り出せます。

C#
foreach (User user in users)
{
Console.WriteLine($"{user.Id}: {user.Name}");
}

5. new Listに追加した値を確認・操作する方法

5-1. インデックスを指定して値を取得する方法

リストの各要素には、0から始まるインデックスが割り当てられます。

C#
List<string> fruits = new List<string>
{
"りんご",
"バナナ",
"みかん"
};

最初の要素を取得する場合は、インデックス0を指定します。

C#
Console.WriteLine(fruits[0]); // りんご

2番目の要素はインデックス1です。

C#
Console.WriteLine(fruits[1]); // バナナ

最後の要素は、Count - 1で取得できます。

C#
Console.WriteLine(fruits[fruits.Count - 1]); // みかん

C#のインデックス演算子を利用できる環境では、^1で末尾の要素を指定することもできます。

C#
Console.WriteLine(fruits[^1]); // みかん

リストが空の場合は末尾の要素が存在しないため、取得前に要素数を確認すると安全です。

C#
if (fruits.Count > 0)
{
Console.WriteLine(fruits[0]);
}

5-2. foreachでListの全要素を取り出す方法

リストの全要素を順番に処理する場合は、foreach文が便利です。

C#
List<int> numbers = new List<int>
{
10,
20,
30
};

foreach (int number in numbers)
{
Console.WriteLine(number);
}

実行結果は次のとおりです。

10
20
30

文字列のリストも同様に処理できます。

C#
List<string> names = new List<string>
{
"田中",
"佐藤",
"鈴木"
};

foreach (string name in names)
{
Console.WriteLine(name);
}

インデックスも必要な場合は、for文を使用できます。

C#
for (int i = 0; i < names.Count; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}

foreachの処理中に同じリストへ要素を追加・削除すると、例外が発生することがあります。要素を削除しながら処理する場合は、後ろからfor文で走査するなどの方法を検討します。

5-3. Countプロパティで要素数を確認する方法

リストに格納されている要素数は、Countプロパティで確認できます。

C#
List<string> names = new List<string>
{
"田中",
"佐藤",
"鈴木"
};

Console.WriteLine(names.Count); // 3

要素を追加すると、Countが増えます。

C#
names.Add("高橋");

Console.WriteLine(names.Count); // 4

要素を削除すると、Countが減ります。

C#
names.Remove("佐藤");

Console.WriteLine(names.Count); // 3

リストが空かどうかは、次のように判断できます。

C#
if (names.Count == 0)
{
Console.WriteLine("リストは空です");
}

1件以上の要素があるか確認する場合は、次のように記述します。

C#
if (names.Count > 0)
{
Console.WriteLine("データがあります");
}

5-4. Containsメソッドで値の有無を確認する方法

指定した値がリストに含まれているか確認する場合は、Containsメソッドを使用します。

C#
List<string> fruits = new List<string>
{
"りんご",
"バナナ",
"みかん"
};

bool exists = fruits.Contains("バナナ");

Console.WriteLine(exists); // True

if文の条件として直接使用できます。

C#
if (fruits.Contains("りんご"))
{
Console.WriteLine("りんごが登録されています");
}

存在しないことを確認する場合は、先頭に!を付けます。

C#
if (!fruits.Contains("ぶどう"))
{
fruits.Add("ぶどう");
}

文字列の比較方法によっては、大文字と小文字が区別されます。

C#
List<string> codes = new List<string> { "ABC" };

Console.WriteLine(codes.Contains("ABC")); // True
Console.WriteLine(codes.Contains("abc")); // False

大文字と小文字を区別せずに検索したい場合は、LINQのAnyなどを利用できます。

C#
using System;
using System.Linq;

bool exists = codes.Any(
code => string.Equals(code, "abc", StringComparison.OrdinalIgnoreCase)
);

5-5. 値を変更・削除する基本的な方法

リストの値を変更する場合は、インデックスを指定して新しい値を代入します。

C#
List<string> fruits = new List<string>
{
"りんご",
"バナナ",
"みかん"
};

fruits[1] = "ぶどう";

Console.WriteLine(fruits[1]); // ぶどう

指定した値を削除する場合は、Removeメソッドを使用します。

C#
fruits.Remove("りんご");

Removeは、指定した値と一致する最初の要素を削除し、削除できたかどうかをboolで返します。

C#
bool removed = fruits.Remove("みかん");

Console.WriteLine(removed); // True

インデックスを指定して削除する場合は、RemoveAtメソッドを使用します。

C#
fruits.RemoveAt(0);

条件に一致する要素をまとめて削除する場合は、RemoveAllメソッドが便利です。

C#
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

numbers.RemoveAll(number => number % 2 == 0);

この例では、偶数がすべて削除されます。

すべての要素を削除して空のリストにする場合は、Clearメソッドを使用します。

C#
fruits.Clear();

Console.WriteLine(fruits.Count); // 0

6. new Listを使うときによくあるエラーと対処法

6-1. Listが見つからないと表示される原因

List<T>を使用したときに、Listが見つからないというエラーが表示される場合は、System.Collections.Generic名前空間が読み込まれていない可能性があります。

ファイルの先頭に次の記述を追加します。

C#
using System.Collections.Generic;

コード全体の例は次のとおりです。

C#
using System;
using System.Collections.Generic;

class Program
{
static void Main()
{
List<int> numbers = new List<int>();
numbers.Add(10);

Console.WriteLine(numbers[0]);
}
}

完全修飾名を使用する方法もあります。

C#
System.Collections.Generic.List<int> numbers =
new System.Collections.Generic.List<int>();

また、listではなくListと記述しているかも確認しましょう。C#では大文字と小文字が区別されます。

C#
List<int> numbers = new List<int>(); // 正しい
// list<int> numbers = new list<int>(); // 誤り

6-2. Listを初期化せずにAddしてNullReferenceExceptionになる原因

リスト型の変数を宣言しても、インスタンスが作成されていなければAddメソッドを使用できません。

次のコードでは、numbersnullが入っています。

C#
List<int>? numbers = null;
numbers.Add(10);

このコードを実行すると、NullReferenceExceptionが発生します。

値を追加する前に、new List<int>()でインスタンスを作成しましょう。

C#
List<int> numbers = new List<int>();
numbers.Add(10);

後から初期化する場合は、次のように記述します。

C#
List<int>? numbers = null;

numbers = new List<int>();
numbers.Add(10);

nullかどうか分からない場合は、null合体代入演算子も利用できます。

C#
numbers ??= new List<int>();
numbers.Add(10);

6-3. 指定した型と異なる値を追加できない理由

List<T>に追加できるのは、基本的にTで指定した型の値です。

List<int>は整数のリストなので、文字列を追加できません。

C#
List<int> numbers = new List<int>();

numbers.Add(10);
// numbers.Add("20"); // コンパイルエラー

文字列を格納したい場合は、List<string>を使用します。

C#
List<string> values = new List<string>();

values.Add("20");

数値として扱いたい文字列は、変換してから追加します。

C#
string input = "20";

if (int.TryParse(input, out int number))
{
numbers.Add(number);
}

ジェネリックの型指定によって、異なる種類の値が誤って混ざるのをコンパイル時に防げます。

6-4. 存在しないインデックスを指定したときのエラー

リストに存在しないインデックスを指定すると、ArgumentOutOfRangeExceptionが発生します。

C#
List<string> names = new List<string>
{
"田中",
"佐藤"
};

Console.WriteLine(names[2]);

このリストの要素数は2ですが、有効なインデックスは01です。

names[0] → 田中
names[1] → 佐藤

インデックスは0から始まるため、有効な最大値はCount - 1です。

安全に取得するには、範囲を確認します。

C#
int index = 2;

if (index >= 0 && index < names.Count)
{
Console.WriteLine(names[index]);
}
else
{
Console.WriteLine("指定した位置に要素がありません");
}

空のリストに対してnames[0]を指定した場合も同じエラーが発生するため、Countの確認が重要です。

6-5. Listを代入しただけでは複製されない点に注意する

次のコードでは、originalcopiedに代入しています。

C#
List<int> original = new List<int> { 10, 20, 30 };
List<int> copied = original;

この代入では、新しいリストは作成されません。originalcopiedは、同じリストのインスタンスを参照します。

そのため、copiedに値を追加すると、originalにも反映されます。

C#
copied.Add(40);

Console.WriteLine(original.Count); // 4
Console.WriteLine(copied.Count); // 4

別のリストとして複製したい場合は、new List<T>のコンストラクターに元のリストを渡します。

C#
List<int> original = new List<int> { 10, 20, 30 };
List<int> copied = new List<int>(original);

copied.Add(40);

Console.WriteLine(original.Count); // 3
Console.WriteLine(copied.Count); // 4

ただし、クラスのオブジェクトを格納したリストでは、要素の参照まで自動的に複製されるわけではありません。オブジェクトも完全に分けたい場合は、それぞれ新しいインスタンスを作る必要があります。

7. new Listに関するよくある疑問

7-1. Listと配列はどちらを使うべきか

List<T>と配列は、どちらも複数の値を管理するために使用できます。ただし、適した場面が異なります。

配列は、基本的に作成時に要素数を決めます。

C#
int[] numbers = new int[3];

numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;

List<T>は、作成後に要素を追加・削除できます。

C#
List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);
numbers.Remove(10);

要素数が固定されており、変更する必要がない場合は配列が適しています。

C#
string[] days =
{
"月曜日",
"火曜日",
"水曜日",
"木曜日",
"金曜日",
"土曜日",
"日曜日"
};

ユーザーの入力、検索結果、商品一覧など、要素数が変化する場合はList<T>が便利です。

迷ったときは、次の基準で考えるとよいでしょう。

  • 要素数が固定されている場合は配列

  • 要素を追加・削除する場合はList<T>

  • サイズが変わる可能性がある場合はList<T>

  • 固定長の単純なデータを扱う場合は配列

7-2. new List<int>()とnew()の違い

通常の記述では、右辺にも型名を指定します。

C#
List<int> numbers = new List<int>();

C# 9以降では、左辺から型を判断できる場合、右辺の型名を省略したターゲット型のnewを使用できます。

C#
List<int> numbers = new();

この2つは、どちらも空のList<int>を作成しています。

C#
List<int> numbers1 = new List<int>();
List<int> numbers2 = new();

値を設定して初期化することもできます。

C#
List<int> numbers = new()
{
10,
20,
30
};

ただし、varnew()だけでは、コンパイラが型を判断できません。

C#
// var numbers = new(); // 型を判断できないためエラー

varを使用する場合は、右辺に型名を記述します。

C#
var numbers = new List<int>();

利用しているC#のバージョンが古い場合は、new()を使用できないことがあります。その場合は、new List<int>()と記述します。

7-3. Listの初期化と値の追加は同時にできるか

コレクション初期化子を使用すれば、リストの作成と値の追加を同時に行えます。

C#
List<int> numbers = new List<int>
{
10,
20,
30
};

文字列のリストも同様です。

C#
List<string> names = new List<string>
{
"田中",
"佐藤",
"鈴木"
};

オブジェクトのリストも初期化できます。

C#
List<Product> products = new List<Product>
{
new Product
{
Id = 1,
Name = "ノート",
Price = 300
},
new Product
{
Id = 2,
Name = "ペン",
Price = 120
}
};

最初から登録するデータが決まっている場合は、コレクション初期化子を使用するとコードが読みやすくなります。

7-4. Listに異なるデータ型を格納できるか

通常、List<T>には指定した型の値だけを格納します。

C#
List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);

異なる型を格納する方法として、List<object>を使用することは可能です。

C#
List<object> values = new List<object>();

values.Add(100);
values.Add("田中");
values.Add(true);

ただし、取り出すときに実際の型を確認したり、型変換したりする必要があります。

C#
foreach (object value in values)
{
if (value is int number)
{
Console.WriteLine($"整数: {number}");
}
else if (value is string text)
{
Console.WriteLine($"文字列: {text}");
}
else if (value is bool flag)
{
Console.WriteLine($"真偽値: {flag}");
}
}

異なる型を無理に1つのリストへ入れると、コードが複雑になりやすくなります。関連するデータをまとめたい場合は、専用のクラスを作成する方法が一般的です。

C#
class UserData
{
public int Id { get; set; }
public string Name { get; set; } = "";
public bool IsActive { get; set; }
}
C#
List<UserData> users = new List<UserData>
{
new UserData
{
Id = 1,
Name = "田中",
IsActive = true
}
};

7-5. Listの要素数に上限はあるか

List<T>の要素数に、すべての環境で共通する単純な固定上限が設定されているわけではありません。実際に格納できる要素数は、主に次の条件によって制限されます。

  • 使用できるメモリ容量

  • 32ビットまたは64ビットなどの実行環境

  • 格納する要素のデータ型やサイズ

  • .NETランタイムや内部配列の制約

  • アプリケーションに設定されたメモリ制限

List<T>は内部で配列を使用しているため、要素が増えると必要なメモリも増加します。非常に大量のデータを1つのリストへ格納すると、メモリ不足によってOutOfMemoryExceptionが発生する可能性があります。

通常のアプリケーションでは、上限値そのものよりも、すべてのデータを一度にメモリへ読み込む必要があるかを考えることが重要です。

データベースから大量のデータを取得する場合は、次のような対策を検討します。

  • ページ単位でデータを取得する

  • 必要な項目だけを取得する

  • 条件を指定して取得件数を減らす

  • ストリーミング処理を利用する

  • 処理済みのデータを適切に解放する

数百件や数千件程度の一般的なデータであれば、通常はList<T>を問題なく利用できます。

まとめ

C#のnew Listは、複数の値を格納できるList<T>の新しいインスタンスを作成するための記述です。

空の整数リストを作成する基本構文は、次のとおりです。

C#
List<int> numbers = new List<int>();

作成と同時に値を設定する場合は、コレクション初期化子を使用できます。

C#
List<int> numbers = new List<int>
{
10,
20,
30
};

値を1件追加する場合はAdd、複数件をまとめて追加する場合はAddRangeを使用します。

C#
numbers.Add(40);
numbers.AddRange(new[] { 50, 60 });

リストの要素は、インデックスやforeach文で取得できます。

C#
Console.WriteLine(numbers[0]);

foreach (int number in numbers)
{
Console.WriteLine(number);
}

List<T>は、作成後に要素を追加・削除できるため、件数が変化するデータの管理に適しています。まずはnew List<T>()で空のリストを作成し、Addで値を追加する基本操作から覚えると、C#のコレクションを理解しやすくなるでしょう。