C#でプログラミングを行っていると、配列やリストの中に格納されている複数の要素を、カンマや改行などの「区切り文字」を挟んで一つの文字列にまとめたい場面が多々あります。
例えば、ログ出力のために配列の中身を一覧表示したり、CSV形式のデータを作成したりする場合です。
このような処理をループ処理で愚直に実装することも可能ですが、C#には非常に強力で便利なstring.Joinメソッドが用意されています。
この記事では、string.Joinの基本的な使い方から、実戦で役立つ応用テクニック、さらにはパフォーマンス面のメリットまで詳しく解説します。
string.Joinメソッドの基本概念
string.Joinは、コレクションの各要素を文字列に変換し、指定した区切り文字で連結するための静的メソッドです。
このメソッドを利用することで、煩雑なループ処理や末尾の区切り文字を削除するといった手間を省くことができます。

string.Joinとは何か?
string.Joinは、.NET Frameworkの初期から存在する非常にポピュラーなメソッドです。
その役割は非常にシンプルで、「複数のデータを一つの文字列に接着する」ことです。
引数として「どのような区切り文字を使うか」と「どのデータを結合するか」を指定するだけで、内部的に効率的な文字列結合処理を行ってくれます。
かつては配列のみを対象としていましたが、現在のC#(.NET 4.0以降)ではIEnumerable<T>に対応しているため、List<T>やLINQの結果に対しても直接呼び出すことが可能です。
また、要素が文字列以外(例えば整数型)であっても、内部で自動的にToString()を呼び出してくれるため、型変換の手間も最小限に抑えられます。
なぜループ処理より推奨されるのか
初心者の方は、foreach文を使って要素を一つずつ文字列に加算していくコードを書きがちです。
しかし、その方法にはいくつかの欠点があります。
まず、コードの可読性です。
ループで結合する場合、「最後の要素の後に区切り文字を入れない」という制御が必要になり、if文による判定や、ループ後に末尾の一文字を削除するといった処理が混入します。
これに対してstring.Joinは、一行で記述できるため意図が明確になります。
次にパフォーマンス上の懸念です。
C#の文字列(string)は不変(Immutable)なオブジェクトであるため、+=演算子で文字列を連結するたびに新しいメモリ領域が確保され、古い文字列は破棄されます。
要素数が多い場合、このメモリの再確保コストが無視できないほど大きくなります。
string.Joinは内部でStringBuilderのような効率的な仕組みを用いて、一度に最適なサイズのメモリを確保しようとするため、非常に高速に動作します。
基本的な使い方:配列とリストの結合
それでは、具体的なプログラムコードを通して使い方を見ていきましょう。
まずは最も一般的な「文字列の配列」および「リスト」を結合する方法です。

配列(Array)を結合する
最もシンプルな形態は、文字列の配列を結合するパターンです。
第一引数に区切り文字、第二引数に配列を指定します。
using System;
class Program
{
static void Main()
{
// 文字列の配列を定義します
string[] fruits = { "リンゴ", "バナナ", "オレンジ" };
// カンマとスペースで結合します
string result = string.Join(", ", fruits);
// 結果を出力します
Console.WriteLine("結合結果: " + result);
}
}
結合結果: リンゴ, バナナ, オレンジ
この例では、", "という文字列を区切り文字として指定しました。
最後の「オレンジ」の後にカンマが付いていないことに注目してください。
これがstring.Joinの最も便利な点です。
リスト(List<T>)を結合する
現代のC#開発では、固定長の配列よりも可変長のList<string>を使用することが多いでしょう。
string.JoinはIEnumerable<string>を引数に取ることができるため、リストもそのまま渡すことができます。
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// リストを作成し、要素を追加します
List<string> members = new List<string> { "田中", "佐藤", "鈴木" };
// 改行文字(Environment.NewLine)で結合します
string result = string.Join(Environment.NewLine, members);
Console.WriteLine("メンバーリスト:");
Console.WriteLine(result);
}
}
メンバーリスト:
田中
佐藤
鈴木
Environment.NewLineを使用することで、実行環境(WindowsやLinux)に応じた適切な改行コードでリストを連結できます。
レポートの出力やコンソールへの整形表示に非常に役立ちます。
数値やオブジェクトの結合
string.Joinは、文字列以外の型が含まれるコレクションに対しても適用可能です。
以前のC#では一度文字列に変換する必要がありましたが、現在のバージョンではジェネリック版のオーバーロードが提供されているため、直接渡すことができます。

数値配列の結合
例えば、整数の配列をハイフンで繋いで一つの文字列にするコードは以下のようになります。
using System;
class Program
{
static void Main()
{
// 整数の配列を定義します
int[] numbers = { 101, 202, 303, 404 };
// パイプ記号で結合します。内部でToString()が呼ばれます。
string result = string.Join(" | ", numbers);
Console.WriteLine("ID一覧: " + result);
}
}
ID一覧: 101 | 202 | 303 | 404
このように、明示的にSelect(x => x.ToString())などを呼び出す必要はありません。
string.Joinが各要素に対してobject.ToStringメソッドを呼び出し、その結果を連結してくれます。
独自のクラス(オブジェクト)を結合する場合
自作したクラスのリストを結合する場合も同様ですが、そのクラスでToString()メソッドをオーバーライドしておくことが重要です。
オーバーライドしていない場合、クラスのフルネーム(型名)が連結されてしまいます。
using System;
using System.Collections.Generic;
class Product
{
public string Name { get; set; }
public int Price { get; set; }
// ToStringをオーバーライドして、結合時の表示形式を定義します
public override string ToString() => $"{Name}({Price}円)";
}
class Program
{
static void Main()
{
var cart = new List<Product>
{
new Product { Name = "消しゴム", Price = 100 },
new Product { Name = "ノート", Price = 250 }
};
// オブジェクトのリストを結合
string summary = string.Join(" + ", cart);
Console.WriteLine("買い物かご: " + summary);
}
}
買い物かご: 消しゴム(100円) + ノート(250円)
応用的な使い方と便利なテクニック
基本的な使い道を理解したところで、次は少し高度なテクニックを見てみましょう。
実務では、単に全部を繋げるだけでなく、特定の条件でフィルタリングしたり、一部だけを抜き出したりすることが求められます。
LINQとの組み合わせ
string.JoinとLINQ(Language Integrated Query)を組み合わせることで、データの加工と結合を一行でスマートに記述できます。
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
string[] names = { "Alice", "Bob", "Charlie", "David", "Eve" };
// 4文字以上の名前だけを抽出し、大文字に変換して結合する
string result = string.Join(", ", names
.Where(n => n.Length >= 5)
.Select(n => n.ToUpper()));
Console.WriteLine("対象者: " + result);
}
}
対象者: ALICE, CHARLIE, DAVID
このように、Whereで絞り込み、Selectで変換した結果をそのままstring.Joinに流し込めます。
これは非常に強力で、C#らしい洗練された書き方と言えます。
範囲を指定して結合する
配列全体ではなく、特定の範囲だけを結合したい場合には、string.Joinのオーバーロードの一つである「開始インデックス」と「要素数」を指定するバージョンを使用します。
using System;
class Program
{
static void Main()
{
string[] alphabet = { "A", "B", "C", "D", "E", "F" };
// インデックス2(C)から、3つの要素を結合します
string partial = string.Join("-", alphabet, 2, 3);
Console.WriteLine("部分結合: " + partial);
}
}
部分結合: C-D-E
大量のデータのうち、特定のページに該当するデータだけを表示したい場合などに、余計な配列のコピーを作ることなく結合できるため効率的です。
特殊な状況での挙動と注意点
プログラムを堅牢にするためには、例外的なケースでの挙動を把握しておく必要があります。
nullや空のコレクションを渡したときにどうなるかを理解しておきましょう。
nullや空文字が含まれる場合
結合対象の配列の中にnullが含まれている場合、string.Joinはそれを空文字列(string.Empty)として扱います。
エラーで停止することはありませんが、区切り文字だけが連続して出力される可能性があります。
| 状況 | 挙動 |
|---|---|
要素が null | 空文字として扱われ、区切り文字は挿入される |
コレクション自体が null | ArgumentNullException がスローされる |
| コレクションが空 | string.Empty (空文字) が返される |
区切り文字が null | 空文字として扱われる(区切りなしで連結) |
以下のサンプルで実際の動きを確認してください。
using System;
class Program
{
static void Main()
{
// 要素にnullや空文字を含む配列
string[] values = { "Start", null, "", "End" };
// 結合結果を確認
string result = string.Join(":", values);
Console.WriteLine("結果: [" + result + "]");
}
}
結果: [Start:: :End]
出力結果を見ると、nullがあった場所にもコロンが挿入され、空白のような状態になっていることがわかります。
もしnullを無視したい場合は、事前にLINQのWhere(x => x != null)を使って除外する必要があります。
パフォーマンスとStringBuilder
「大量の文字列を結合する場合、StringBuilderを使うべきか、string.Joinを使うべきか」という疑問を抱くかもしれません。
結論から言うと、既にコレクションとしてデータが揃っているなら string.Join が最適です。
なぜなら、string.Joinは内部的に全ての要素の合計長をあらかじめ計算し、一度のメモリ確保で済むように最適化されているからです。
一方、ループの中で複雑な条件判定を繰り返しながら、都度文字列を生成して追加していくようなケースでは、StringBuilderを明示的に使う方が柔軟で効率的になる場合があります。
使い分けの目安としては、「既存のリストを単純に繋げるならJoin」、「複雑な構築プロセスが必要ならStringBuilder」と覚えておけば間違いありません。

まとめ
string.Joinメソッドは、C#において配列やリストを扱う上で欠かせない非常に便利なツールです。
ループ処理を自前で書くよりもコードが簡潔になり、意図が伝わりやすく、かつパフォーマンスも最適化されているという三拍子揃ったメリットがあります。
今回の内容をまとめると以下の通りです。
- 文字列配列だけでなく、
List<T>や数値型のコレクションにも使用できる。 - 区切り文字は文字列だけでなく文字型(
char)も指定可能。 - LINQと組み合わせることで、フィルタリングや加工後の結合も一行で記述できる。
- コレクション内の
nullは空文字として扱われる。 - 大量のデータを結合する際も、内部的に最適化されているため高速である。
日常的なログ出力から、業務システムでのデータフォーマット変換まで、幅広いシーンで活用してください。
この記事を通じて、あなたのC#コーディングがより効率的でスマートなものになれば幸いです。
