はじめに
new int[] { 1, 2, 3 } とか new List<string> { "a", "b" } みたいな書き方、何度書いても「くどいな」と感じていました。
最近、コレクション式(Collection Expression)という構文を知り、使い始めてみたら思いのほか便利だったので整理しておきます。
環境
- .NET 10.0
- C# 14.0
- Visual Studio 2026
コレクション式とは
[ と ] で囲むだけで、配列・リスト・スパンなどのコレクションを初期化できる構文です。C# 12(.NET 8)で導入されました。
// 今まで
int[] array = new int[] { 1, 2, 3 };
List<int> list = new List<int> { 1, 2, 3 };
// コレクション式
int[] array = [1, 2, 3];
List<int> list = [1, 2, 3];
見た目がスッキリするのはもちろんですが、個人的に一番ありがたいのは型が変わっても書き方を変えなくていいことです。int[] を List<int> にリファクタリングしても、右辺はそのままです。
空のコレクションも簡潔に
// 今まで
int[] empty = Array.Empty<int>();
List<int> emptyList = new List<int>();
// コレクション式
int[] empty = [];
List<int> emptyList = [];
Array.Empty<int>() を毎回書かなくていいのは地味に楽です。
Span にも使える
Span<int> span = [1, 2, 3];
ReadOnlySpan<char> chars = ['a', 'b', 'c'];
パフォーマンス重視の場面で使う Span<T> も同じ書き方で初期化できるのは統一感があっていいですね。
スプレッド演算子 .. でコレクションを結合できる
[...] の中で .. を使うと、既存のコレクションを展開して結合できます。
int[] a = [1, 2, 3];
int[] b = [4, 5, 6];
int[] merged = [..a, ..b]; // [1, 2, 3, 4, 5, 6]
int[] withExtra = [0, ..a, ..b, 7]; // [0, 1, 2, 3, 4, 5, 6, 7]
Concat や AddRange でやっていたことが1行で書けます。
yield return や式本体メソッドとの組み合わせ
yield return で返すオブジェクトの引数として使う
yield return で返すオブジェクトの引数に、コレクション式を使うことはできます。たとえば ValidationResult の第2引数(IEnumerable<string>)はこう書けます。
private IEnumerable<ValidationResult> ValidateName()
{
if (string.IsNullOrEmpty(Name))
yield return new ValidationResult("名前は必須です", ["Name"]); // ここ
}
今まで new[] { "Name" } と書いていた部分が ["Name"] になるだけですが、スッキリします。
スプレッドで複数メソッドの結果をまとめて返す
IValidatableObject を実装するときに、バリデーションロジックをサブメソッドに分けることがよくあります。
従来の foreach を使った書き方だとこうなります。
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach (var result in ValidateName())
yield return result;
foreach (var result in ValidateAge())
yield return result;
}
これをコレクション式とスプレッド演算子を使った式本体メソッドで書き直すとこうなります。
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
=> [..ValidateName(), ..ValidateAge()];
foreach のネストが消えて、「このメソッドたちの結果をまとめて返す」という意図が一行で読み取れます。バリデーションの項目が増えてもここに ..ValidateXxx() を足すだけなので、見通しも良くなります。
ただし、この書き方は yield return のような遅延評価ではなく、全要素を一度インメモリのコレクションに格納してから返します。バリデーション結果のような少数の要素なら実用上問題にはなりませんが、大量データや副作用のある列挙の場合は yield return の方が適しています。
C# 13 での変化
C# 13 では params が配列だけでなく、ReadOnlySpan<T> をはじめとするコレクション型にも対応しました(params コレクション)。
void Print(params ReadOnlySpan<string> values) { }
Print("Alice", "Bob", "Carol"); // そのまま渡せる
C# 13 では、params パラメーターの型として、コレクション式の変換先として認識される型も使えるようになりました。params と ReadOnlySpan<T> の組み合わせは不要な配列割り当てを避けやすいため、ライブラリ API 側で活用される場面が増えそうです。
まとめ
-
コレクション式(
[...])で配列・リスト・Span などを統一した書き方で初期化できる(C# 12〜) - 型が変わっても右辺の書き方を変えなくていいのが地味にありがたい
-
スプレッド演算子(
..)でコレクションの展開・結合が簡潔に書ける -
yield returnで返すオブジェクトの引数として使えるほか、=> [..Method1(), ..Method2()]の形で複数メソッドの結果をまとめて返すのが読みやすい(ただし即時評価) - C# 13 では
paramsがコレクション型にも対応(params コレクション)
書いてみると「今まで new[] { } とか Concat とか書いてたのは何だったんだ」という気持ちになります。
参考になったら いいね や ストック をお願いします!
参考
関連リンク
技術ブログでも学びや検証内容をまとめています。