C#のJoin完全ガイド|string.Joinで配列・Listをカンマ区切りに結合する方法とLINQ Joinとの違い

はじめに

C#で「join」と検索すると、主に2つの意味が出てきます。1つは、配列やListの要素をカンマ区切りなどで1つの文字列にまとめるstring.Joinです。もう1つは、LINQで2つのコレクションをキーによって結合するJoinです。

たとえば、次のように配列の中身をカンマ区切りで表示したい場合は、string.Joinを使います。

C#
string[] fruits = { "Apple", "Banana", "Orange" };

string result = string.Join(",", fruits);

Console.WriteLine(result);

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

C#
Apple,Banana,Orange

一方で、社員一覧と部署一覧を部署IDで結び付けたいような場合は、LINQのJoinを使います。

この記事では、C#のJoinについて、特に利用頻度の高いstring.Joinを中心に、配列・List・数値配列・オブジェクトのListをカンマ区切りで結合する方法を解説します。さらに、混同しやすいLINQのJoinとの違いも整理します。

1. C#のJoinとは?まず押さえるべき2つの意味

C#で「Join」と言った場合、文脈によって意味が変わります。

よく使われるのは、次の2つです。

C#
string.Join
C#
LINQのJoin

どちらも「結合」という意味では共通していますが、目的は大きく異なります。

string.Joinは、複数の値を1つの文字列に結合するために使います。たとえば、配列やListの中身をカンマ区切りで表示したいときに便利です。

一方、LINQのJoinは、2つのコレクションを共通のキーで結合するために使います。SQLのINNER JOINに近い処理です。

1-1. string.Joinは配列・Listなどを区切り文字で1つの文字列に結合するメソッド

string.Joinは、配列やListなどの複数要素を、指定した区切り文字でつないで1つの文字列にするメソッドです。

たとえば、次のような配列があるとします。

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

これをカンマ区切りの文字列にしたい場合は、次のように書きます。

C#
string result = string.Join(",", names);

Console.WriteLine(result);

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

C#
田中,佐藤,鈴木

カンマの後ろにスペースを入れたい場合は、区切り文字を", "にします。

C#
string result = string.Join(", ", names);

Console.WriteLine(result);

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

C#
田中, 佐藤, 鈴木

このように、string.Joinは「配列やListを文字列として見やすく整形したい」ときに非常によく使われます。

1-2. LINQ Joinは2つのコレクションをキーで結合するメソッド

LINQのJoinは、文字列を結合するためのものではありません。

LINQのJoinは、2つのコレクションを共通するキーで結合するために使います。

たとえば、社員データと部署データがあるとします。

C#
var employees = new[]
{
new { Id = 1, Name = "田中", DepartmentId = 10 },
new { Id = 2, Name = "佐藤", DepartmentId = 20 }
};

var departments = new[]
{
new { Id = 10, Name = "営業部" },
new { Id = 20, Name = "開発部" }
};

社員のDepartmentIdと部署のIdを結び付ける場合、LINQのJoinを使います。

C#
var query = employees.Join(
departments,
employee => employee.DepartmentId,
department => department.Id,
(employee, department) => new
{
EmployeeName = employee.Name,
DepartmentName = department.Name
}
);

foreach (var item in query)
{
Console.WriteLine($"{item.EmployeeName}: {item.DepartmentName}");
}

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

C#
田中: 営業部
佐藤: 開発部

これは、文字列をカンマ区切りにする処理ではなく、データ同士をキーで関連付ける処理です。

1-3. 「C# join」で検索する人が混同しやすいポイント

「C# join」で検索する人が混同しやすいのは、string.JoinとLINQのJoinがどちらも「Join」という名前を持っている点です。

目的別に整理すると、次のようになります。

やりたいこと使うもの
配列をカンマ区切りの文字列にしたいstring.Join
Listをカンマ区切りの文字列にしたいstring.Join
数値配列を文字列として結合したいstring.Join
オブジェクトの特定プロパティを結合したいSelect + string.Join
2つのコレクションをIDで結合したいLINQのJoin
SQLのINNER JOINのような処理をしたいLINQのJoin

つまり、「配列やListの要素を1つの文字列にしたい」ならstring.Join、「2つのデータ群をキーで結びたい」ならLINQのJoinを使います。

2. string.Joinの基本構文と使い方

string.Joinは、C#で配列やListの要素を区切り文字付きで結合するときに使う基本的なメソッドです。

ログ出力、画面表示、CSV風の文字列作成、ID一覧の生成など、実務でも頻繁に使われます。

2-1. string.Joinの基本構文

string.Joinの基本構文は次のとおりです。

C#
string.Join(区切り文字, 結合したい値の集まり)

具体的には、次のように使います。

C#
string[] values = { "A", "B", "C" };

string result = string.Join(",", values);

Console.WriteLine(result);

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

C#
A,B,C

第一引数に区切り文字、第二引数に配列やListなどの値の集まりを指定します。

2-2. 区切り文字にカンマを指定する方法

カンマ区切りにしたい場合は、第一引数に","を指定します。

C#
string[] items = { "red", "blue", "green" };

string result = string.Join(",", items);

Console.WriteLine(result);

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

C#
red,blue,green

カンマの後ろにスペースを入れて見やすくしたい場合は、", "を指定します。

C#
string result = string.Join(", ", items);

Console.WriteLine(result);

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

C#
red, blue, green

画面表示用には", "、CSVのように機械的に扱う文字列には","を使うことが多いです。

2-3. separatorとvaluesに指定する引数の意味

string.Joinでは、よく次のような引数名で説明されます。

C#
string.Join(separator, values)

separatorは、要素と要素の間に挟む区切り文字です。

C#
","
", "
" "
"\n"
"\t"

valuesは、結合したい値の集まりです。

C#
string[] values = { "A", "B", "C" };
List<string> values = new List<string> { "A", "B", "C" };
IEnumerable<string> values = items.Select(x => x.Name);

たとえば、次のコードでは、", "separatornamesvaluesです。

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

string result = string.Join(", ", names);

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

C#
田中, 佐藤, 鈴木

2-4. Joinはstringクラスの静的メソッドである

string.Joinは、stringクラスの静的メソッドです。

そのため、次のようにstring.Join(...)という形で呼び出します。

C#
string result = string.Join(",", values);

配列やListのインスタンスに対して、次のように呼び出すわけではありません。

C#
// 誤り
values.Join(",");

C#では拡張メソッドのように見えるLINQメソッドも多いため混乱しやすいですが、文字列結合で使うJoinは基本的にstring.Joinと書きます。

3. 配列をstring.Joinでカンマ区切りに結合する方法

配列をカンマ区切りで結合するのは、string.Joinの代表的な使い方です。

string[]だけでなく、int[]などの数値配列も結合できます。

3-1. string配列をカンマ区切りの文字列にする

文字列配列をカンマ区切りにする例です。

C#
string[] fruits = { "Apple", "Banana", "Orange" };

string result = string.Join(",", fruits);

Console.WriteLine(result);

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

C#
Apple,Banana,Orange

カンマの後ろにスペースを入れる場合は、次のようにします。

C#
string result = string.Join(", ", fruits);

Console.WriteLine(result);

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

C#
Apple, Banana, Orange

画面に表示する文字列であれば、スペース付きの", "の方が読みやすいことが多いです。

3-2. int配列など数値配列を結合する

string.Joinは、int[]のような数値配列にも使えます。

C#
int[] numbers = { 1, 2, 3, 4, 5 };

string result = string.Join(",", numbers);

Console.WriteLine(result);

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

C#
1,2,3,4,5

数値は内部的に文字列化されて結合されます。

カンマの後ろにスペースを入れる場合は、次のようにします。

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

string result = string.Join(", ", numbers);

Console.WriteLine(result);

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

C#
10, 20, 30

ID一覧を作るときなどにもよく使われます。

C#
int[] ids = { 101, 102, 103 };

string idText = string.Join(",", ids);

Console.WriteLine(idText);

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

C#
101,102,103

3-3. 区切り文字をカンマ以外に変更する

string.Joinでは、区切り文字はカンマに限定されません。

たとえば、スラッシュ区切りにする場合は次のようにします。

C#
string[] parts = { "2025", "04", "01" };

string result = string.Join("/", parts);

Console.WriteLine(result);

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

C#
2025/04/01

ハイフン区切りにすることもできます。

C#
string[] codes = { "ABC", "001", "XYZ" };

string result = string.Join("-", codes);

Console.WriteLine(result);

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

C#
ABC-001-XYZ

区切り文字には、任意の文字列を指定できます。

C#
string[] words = { "C#", "Java", "Python" };

string result = string.Join(" | ", words);

Console.WriteLine(result);

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

C#
C# | Java | Python

3-4. 改行区切り・スペース区切り・タブ区切りで結合する

改行区切りにしたい場合は、Environment.NewLineを使うのがおすすめです。

C#
string[] lines = { "1行目", "2行目", "3行目" };

string result = string.Join(Environment.NewLine, lines);

Console.WriteLine(result);

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

C#
1行目
2行目
3行目

スペース区切りにする場合は、" "を指定します。

C#
string[] words = { "Hello", "C#", "World" };

string result = string.Join(" ", words);

Console.WriteLine(result);

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

C#
Hello C# World

タブ区切りにする場合は、"\t"を指定します。

C#
string[] columns = { "ID", "Name", "Age" };

string result = string.Join("\t", columns);

Console.WriteLine(result);

実行結果は、タブで区切られた文字列になります。

C#
ID	Name	Age

4. Listをstring.Joinでカンマ区切りに結合する方法

string.Joinは配列だけでなく、List<T>にも使えます。

List<string>List<int>をそのまま渡せるため、実務では配列よりもListに対して使う機会が多いかもしれません。

4-1. List<string>をカンマ区切りにする

List<string>をカンマ区切りにする例です。

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

string result = string.Join(",", names);

Console.WriteLine(result);

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

C#
田中,佐藤,鈴木

カンマの後ろにスペースを入れたい場合は、次のようにします。

C#
string result = string.Join(", ", names);

Console.WriteLine(result);

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

C#
田中, 佐藤, 鈴木

4-2. List<int>をカンマ区切りにする

List<int>も同じように結合できます。

C#
List<int> scores = new List<int>
{
80,
90,
75
};

string result = string.Join(",", scores);

Console.WriteLine(result);

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

C#
80,90,75

数値を画面表示やログ出力に使いたい場合にも便利です。

C#
List<int> ids = new List<int> { 1001, 1002, 1003 };

Console.WriteLine($"対象ID: {string.Join(", ", ids)}");

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

C#
対象ID: 1001, 1002, 1003

4-3. IEnumerable<T>をそのままJoinに渡す

string.Joinには、IEnumerable<T>を受け取れるオーバーロードがあります。

そのため、LINQで処理した結果をそのまま渡すことができます。

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

var evenNumbers = numbers.Where(n => n % 2 == 0);

string result = string.Join(",", evenNumbers);

Console.WriteLine(result);

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

C#
2,4

WhereSelectの結果はIEnumerable<T>なので、ToArray()ToList()に変換しなくてもstring.Joinに渡せます。

C#
var names = users.Select(user => user.Name);

string result = string.Join(", ", names);

この書き方は、実務でもよく使われます。

4-4. 配列とListで書き方はどう違うか

配列とListで、string.Joinの書き方はほとんど同じです。

配列の場合は次のように書きます。

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

string result = string.Join(", ", names);

Listの場合は次のように書きます。

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

string result = string.Join(", ", names);

違いは、値を保持している型が配列かListかだけです。

string.Joinに渡す部分は同じです。

C#
string.Join(", ", values)

そのため、配列でもListでも「区切り文字」と「値の集まり」を渡す、と覚えておけば問題ありません。

5. オブジェクトのListをJoinする方法

実務では、単純な文字列や数値だけでなく、オブジェクトのListを扱うことも多いです。

たとえば、次のようなUserクラスがあるとします。

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

このようなオブジェクトのListをstring.Joinする場合は、どのプロパティを文字列化するかを意識する必要があります。

5-1. Selectで特定プロパティだけを取り出して結合する

オブジェクトのListから特定のプロパティだけを取り出して結合する場合は、LINQのSelectを使います。

C#
List<User> users = new List<User>
{
new User { Id = 1, Name = "田中", Email = "tanaka@example.com" },
new User { Id = 2, Name = "佐藤", Email = "sato@example.com" },
new User { Id = 3, Name = "鈴木", Email = "suzuki@example.com" }
};

string result = string.Join(", ", users.Select(user => user.Name));

Console.WriteLine(result);

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

C#
田中, 佐藤, 鈴木

メールアドレスだけを結合する場合は、次のようにします。

C#
string emails = string.Join(",", users.Select(user => user.Email));

Console.WriteLine(emails);

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

C#
tanaka@example.com,sato@example.com,suzuki@example.com

オブジェクトのListでは、Selectで必要な値だけに変換してからstring.Joinするのが基本です。

5-2. ToStringを利用してオブジェクトを文字列化する

オブジェクトをそのままstring.Joinに渡すこともできます。

ただし、その場合は各オブジェクトのToString()の結果が使われます。

C#
string result = string.Join(", ", users);

Console.WriteLine(result);

UserクラスでToString()をオーバーライドしていない場合、期待した表示にならないことがあります。

たとえば、次のような結果になる可能性があります。

C#
User, User, User

わかりやすい文字列にしたい場合は、ToString()をオーバーライドします。

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

public override string ToString()
{
return $"{Id}:{Name}";
}
}

この状態でstring.Joinすると、次のように表示できます。

C#
string result = string.Join(", ", users);

Console.WriteLine(result);

実行結果の例です。

C#
1:田中, 2:佐藤, 3:鈴木

ただし、実務ではToString()に依存するより、Selectで明示的に整形する方が意図が伝わりやすいことも多いです。

5-3. 複数プロパティを整形してJoinする

複数のプロパティを組み合わせて結合したい場合も、Selectを使うと簡単です。

C#
string result = string.Join(", ", users.Select(user => $"{user.Id}:{user.Name}"));

Console.WriteLine(result);

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

C#
1:田中, 2:佐藤, 3:鈴木

メールアドレス付きで表示することもできます。

C#
string result = string.Join(
Environment.NewLine,
users.Select(user => $"{user.Name} <{user.Email}>")
);

Console.WriteLine(result);

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

C#
田中 <tanaka@example.com>
佐藤 <sato@example.com>
鈴木 <suzuki@example.com>

このように、Selectで1件ごとの表示形式を作り、最後にstring.Joinでつなぐのが実用的な書き方です。

5-4. CSV風の文字列を作るときの注意点

string.Joinを使うと、CSV風の文字列を簡単に作れます。

C#
string csvLine = string.Join(",", users.Select(user => user.Name));

Console.WriteLine(csvLine);

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

C#
田中,佐藤,鈴木

ただし、本格的なCSVを作る場合は注意が必要です。

値の中にカンマ、ダブルクォーテーション、改行が含まれる可能性があるためです。

たとえば、次のような名前があるとします。

C#
string name = "田中,太郎";

この値を単純にカンマ区切りにすると、CSVとして読み込むときに列がずれる可能性があります。

C#
田中,太郎,佐藤

CSVとして正しく扱うには、必要に応じてダブルクォーテーションで囲み、値の中のダブルクォーテーションをエスケープする必要があります。

簡易的なCSVエスケープ関数の例です。

C#
static string EscapeCsv(string value)
{
if (value.Contains(",") || value.Contains("\"") || value.Contains("\n"))
{
return $"\"{value.Replace("\"", "\"\"")}\"";
}

return value;
}

使うときは次のようにします。

C#
string csvLine = string.Join(",", users.Select(user => EscapeCsv(user.Name)));

単純な表示用ならstring.Joinだけで十分ですが、ファイル出力や外部連携でCSVを扱う場合は、CSVライブラリの利用も検討した方が安全です。

6. string.Joinでよくあるエラーと注意点

string.Joinは便利ですが、nullや空配列、空文字の扱いで迷うことがあります。

ここでは、よくある注意点を整理します。

6-1. nullを渡した場合の挙動

string.Joinに渡す値の集まり自体がnullの場合は、例外が発生します。

C#
string[]? values = null;

string result = string.Join(",", values);

このような場合、ArgumentNullExceptionが発生します。

そのため、配列やListがnullになる可能性がある場合は、事前に空配列を使うなどの対策をします。

C#
string[]? values = null;

string result = string.Join(",", values ?? Array.Empty<string>());

Console.WriteLine(result);

この場合、結果は空文字になります。

C#

Listの場合も同じように対策できます。

C#
List<string>? names = null;

string result = string.Join(", ", names ?? Enumerable.Empty<string>());

Console.WriteLine(result);

6-2. 空の配列・空のListを渡した場合の結果

空の配列をstring.Joinに渡すと、結果は空文字になります。

C#
string[] values = Array.Empty<string>();

string result = string.Join(",", values);

Console.WriteLine($"[{result}]");

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

C#
[]

空のListでも同じです。

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

string result = string.Join(",", values);

Console.WriteLine($"[{result}]");

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

C#
[]

要素がないため、区切り文字も出力されません。

6-3. 要素にnullが含まれる場合の結果

配列やListの中にnull要素が含まれる場合、その要素は空文字として扱われます。

C#
string?[] values = { "A", null, "C" };

string result = string.Join(",", values);

Console.WriteLine(result);

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

C#
A,,C

nullの部分が空文字として扱われるため、カンマが連続します。

カンマの後ろにスペースを入れている場合は、次のようになります。

C#
string?[] values = { "A", null, "C" };

string result = string.Join(", ", values);

Console.WriteLine(result);

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

C#
A, , C

nullを除外したい場合は、Whereを使います。

C#
string?[] values = { "A", null, "C" };

string result = string.Join(",", values.Where(value => value != null));

Console.WriteLine(result);

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

C#
A,C

6-4. カンマの後ろにスペースを入れたい場合

カンマの後ろにスペースを入れたい場合は、区切り文字に", "を指定します。

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

string result = string.Join(", ", names);

Console.WriteLine(result);

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

C#
田中, 佐藤, 鈴木

","", "は見た目が異なります。

C#
string.Join(",", names)   // 田中,佐藤,鈴木
string.Join(", ", names) // 田中, 佐藤, 鈴木

CSVのようにデータとして扱う場合は","、画面表示やメッセージ文として見せる場合は", "を使うことが多いです。

6-5. 最後の要素の後ろに区切り文字は付くのか

string.Joinでは、最後の要素の後ろに区切り文字は付きません。

C#
string[] values = { "A", "B", "C" };

string result = string.Join(",", values);

Console.WriteLine(result);

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

C#
A,B,C

最後に余分なカンマは付きません。

つまり、次のようにはなりません。

C#
A,B,C,

ループで手動連結すると、最後のカンマを削除する処理が必要になることがあります。

C#
string result = "";

foreach (var value in values)
{
result += value + ",";
}

result = result.TrimEnd(',');

しかし、string.Joinを使えば、最後の区切り文字を気にする必要がありません。

7. string.Joinと文字列連結の違い

C#で文字列をつなぐ方法は、string.Join以外にもあります。

代表的なものは、+演算子、文字列補間、StringBuilderです。

目的によって使い分けることが大切です。

7-1. +演算子で連結する場合との違い

+演算子は、少数の文字列を結合する場合に便利です。

C#
string firstName = "Taro";
string lastName = "Yamada";

string fullName = lastName + " " + firstName;

Console.WriteLine(fullName);

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

C#
Yamada Taro

また、文字列補間を使うと読みやすく書けます。

C#
string fullName = $"{lastName} {firstName}";

一方、配列やListのような複数要素を区切り文字付きで結合する場合は、string.Joinの方が向いています。

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

string result = string.Join(", ", names);

+演算子で同じことをしようとすると、ループや最後の区切り文字の処理が必要になり、コードが複雑になりがちです。

7-2. StringBuilderを使う場合との違い

StringBuilderは、文字列を何度も追加して組み立てる場合に使われます。

C#
var builder = new StringBuilder();

builder.Append("Name: ");
builder.Append("田中");
builder.Append(", Age: ");
builder.Append(30);

string result = builder.ToString();

Console.WriteLine(result);

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

C#
Name: 田中, Age: 30

複雑な文章や複数行のテキストを段階的に作る場合は、StringBuilderが適しています。

一方で、配列やListの要素を単純に区切り文字で結合するだけなら、string.Joinの方が簡潔です。

C#
string result = string.Join(", ", names);

StringBuilderで同じ処理を書くと、余分な区切り文字を避けるための制御が必要になることがあります。

C#
var builder = new StringBuilder();

for (int i = 0; i < names.Length; i++)
{
if (i > 0)
{
builder.Append(", ");
}

builder.Append(names[i]);
}

string result = builder.ToString();

このケースでは、string.Joinの方が読みやすく保守しやすいです。

7-3. ループで手動連結するよりstring.Joinが向いているケース

次のような処理では、ループで手動連結するよりstring.Joinが向いています。

C#
List<string> tags = new List<string>
{
"C#",
".NET",
"LINQ"
};

string result = string.Join(", ", tags);

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

C#
C#, .NET, LINQ

手動で書くと、次のようになります。

C#
string result = "";

for (int i = 0; i < tags.Count; i++)
{
if (i > 0)
{
result += ", ";
}

result += tags[i];
}

このようなコードは、string.Joinを使えば1行で表現できます。

C#
string result = string.Join(", ", tags);

「複数要素を同じ区切り文字でつなぐ」という目的が明確な場合は、string.Joinを使うのが自然です。

7-4. 可読性と保守性の観点での使い分け

可読性と保守性を考えると、次のように使い分けるとよいでしょう。

やりたいこと向いている方法
少数の文字列を組み合わせる文字列補間
配列やListを区切り文字で結合するstring.Join
複雑な長文を段階的に組み立てるStringBuilder
LINQで加工した結果を文字列にするSelect + string.Join

たとえば、名前と年齢を表示するだけなら文字列補間が読みやすいです。

C#
string message = $"{name}さんは{age}歳です。";

タグ一覧を表示するなら、string.Joinが適しています。

C#
string tagText = string.Join(", ", tags);

複数行のレポートを作るなら、StringBuilderが向いています。

C#
var builder = new StringBuilder();

builder.AppendLine("レポート");
builder.AppendLine("--------");
builder.AppendLine($"件数: {count}");

string report = builder.ToString();

それぞれの役割を理解して使い分けることが大切です。

8. string.Joinの主なオーバーロード

string.Joinには複数のオーバーロードがあります。

オーバーロードとは、同じメソッド名でも引数の型や数が異なる複数の定義があることです。

よく使うものを理解しておけば、配列、List、LINQの結果などに柔軟に対応できます。

8-1. string.Join(string separator, string[] values)

文字列配列を結合する基本的なオーバーロードです。

C#
string[] values = { "A", "B", "C" };

string result = string.Join(",", values);

Console.WriteLine(result);

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

C#
A,B,C

string[]をカンマ区切りや改行区切りにしたい場合に使います。

C#
string result = string.Join(Environment.NewLine, values);

8-2. string.Join(string separator, IEnumerable<string> values)

IEnumerable<string>を結合するオーバーロードです。

List<string>やLINQの結果を渡せます。

C#
List<string> values = new List<string> { "A", "B", "C" };

string result = string.Join(", ", values);

Console.WriteLine(result);

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

C#
A, B, C

LINQのWhereを使った結果もそのまま渡せます。

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

var filtered = names.Where(name => name.StartsWith("佐"));

string result = string.Join(", ", filtered);

Console.WriteLine(result);

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

C#
佐藤

8-3. string.Join<T>(string separator, IEnumerable<T> values)

ジェネリックなIEnumerable<T>を結合するオーバーロードです。

intDateTimeなど、文字列以外の型にも使えます。

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

string result = string.Join(",", numbers);

Console.WriteLine(result);

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

C#
1,2,3

DateTimeのListにも使えます。

C#
List<DateTime> dates = new List<DateTime>
{
new DateTime(2025, 1, 1),
new DateTime(2025, 1, 2)
};

string result = string.Join(", ", dates);

Console.WriteLine(result);

ただし、DateTimeをそのまま結合すると、環境やカルチャによって表示形式が変わることがあります。

表示形式を固定したい場合は、Selectで文字列化してから結合します。

C#
string result = string.Join(
", ",
dates.Select(date => date.ToString("yyyy-MM-dd"))
);

Console.WriteLine(result);

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

C#
2025-01-01, 2025-01-02

8-4. params object[]を使ったJoin

string.Joinには、複数のオブジェクトを直接渡せる形もあります。

C#
string result = string.Join(", ", "A", 1, true);

Console.WriteLine(result);

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

C#
A, 1, True

ただし、実務では配列やList、LINQの結果を渡すケースの方が多いです。

複数の固定値を結合するだけなら、文字列補間の方が読みやすい場合もあります。

C#
string result = $"{name}, {age}, {email}";

一方、値の数が可変であれば、string.Joinが向いています。

8-5. .NETのバージョンによる違い

string.Joinは昔からある基本的なメソッドですが、.NETのバージョンによって利用できるオーバーロードが異なる場合があります。

現在のC#/.NETでは、配列、IEnumerable<string>IEnumerable<T>などを扱えるため、ListやLINQの結果も自然に渡せます。

ただし、古い.NET Framework環境では、一部のオーバーロードが使えない場合があります。

たとえば、古い環境でIEnumerable<T>を直接渡せない場合は、ToArray()で配列に変換してから渡す方法があります。

C#
var values = numbers.Select(n => n.ToString());

string result = string.Join(",", values.ToArray());

新しい.NET環境では、次のようにそのまま書けることが多いです。

C#
string result = string.Join(",", numbers);

古いプロジェクトを保守している場合は、ターゲットフレームワークに注意しましょう。

9. LINQ Joinとの違い

string.JoinとLINQのJoinは、名前は似ていますが役割がまったく違います。

string.Joinは文字列を作るためのメソッドです。

LINQのJoinは、コレクション同士をキーで結合するためのメソッドです。

9-1. LINQ Joinは文字列結合ではなくコレクション同士の結合

LINQのJoinは、配列やListの要素をカンマ区切りにするためのものではありません。

たとえば、次のような商品一覧とカテゴリ一覧があるとします。

C#
var products = new[]
{
new { Id = 1, Name = "ノートPC", CategoryId = 10 },
new { Id = 2, Name = "マウス", CategoryId = 20 }
};

var categories = new[]
{
new { Id = 10, Name = "PC" },
new { Id = 20, Name = "周辺機器" }
};

商品にカテゴリ名を紐づけたい場合、LINQのJoinを使います。

C#
var result = products.Join(
categories,
product => product.CategoryId,
category => category.Id,
(product, category) => new
{
ProductName = product.Name,
CategoryName = category.Name
}
);

これは「文字列を結合する」のではなく、「商品データとカテゴリデータを結合する」処理です。

9-2. LINQ Joinの基本構文

LINQのJoinの基本構文は次のとおりです。

C#
outer.Join(
inner,
outerKeySelector,
innerKeySelector,
resultSelector
)

それぞれの意味は次のとおりです。

引数意味
outer外側のコレクション
inner内側のコレクション
outerKeySelector外側コレクションの結合キー
innerKeySelector内側コレクションの結合キー
resultSelector結合後に作る結果

具体例を見てみます。

C#
var result = products.Join(
categories,
product => product.CategoryId,
category => category.Id,
(product, category) => new
{
Product = product.Name,
Category = category.Name
}
);

product.CategoryIdcategory.Idが一致するものを結合しています。

9-3. SQLのINNER JOINに近い使い方

LINQのJoinは、SQLのINNER JOINに近い使い方をします。

SQLで書くと、次のような処理です。

SQL
SELECT
Products.Name,
Categories.Name
FROM Products
INNER JOIN Categories
ON Products.CategoryId = Categories.Id

C#のLINQでは、次のように書けます。

C#
var result = products.Join(
categories,
product => product.CategoryId,
category => category.Id,
(product, category) => new
{
ProductName = product.Name,
CategoryName = category.Name
}
);

クエリ構文で書くこともできます。

C#
var result =
from product in products
join category in categories
on product.CategoryId equals category.Id
select new
{
ProductName = product.Name,
CategoryName = category.Name
};

SQLに慣れている人は、クエリ構文の方が読みやすい場合もあります。

9-4. string.JoinとLINQ Joinの使い分け

string.JoinとLINQのJoinは、目的で使い分けます。

目的使用するJoin
配列をカンマ区切りにしたいstring.Join
Listを文字列にしたいstring.Join
ID一覧を文字列にしたいstring.Join
オブジェクトのNameだけを連結したいSelect + string.Join
社員と部署を部署IDで結合したいLINQのJoin
商品とカテゴリをカテゴリIDで結合したいLINQのJoin

文字列を作るならstring.Join、データ同士を関連付けるならLINQのJoinです。

9-5. 「配列をカンマ区切りにしたい」ときはLINQ Joinではなくstring.Joinを使う

配列をカンマ区切りにしたい場合は、LINQのJoinではなくstring.Joinを使います。

正しい書き方は次のとおりです。

C#
string[] values = { "A", "B", "C" };

string result = string.Join(",", values);

Console.WriteLine(result);

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

C#
A,B,C

LINQのJoinは、次のような目的では使いません。

C#
// 配列をカンマ区切りにしたいだけならLINQ Joinは不要

C# joinで調べていて、やりたいことが「配列を1つの文字列にしたい」なら、まずstring.Joinを使うと覚えておきましょう。

10. LINQとstring.Joinを組み合わせる実践例

string.Joinは、LINQと組み合わせることでさらに便利になります。

絞り込み、変換、重複除外、並び替えを行った後に、結果をカンマ区切りの文字列にできます。

10-1. Whereで絞り込んだ結果をカンマ区切りにする

Whereで条件に合う要素だけを取り出し、その結果をstring.Joinで結合できます。

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

string result = string.Join(",", numbers.Where(n => n % 2 == 0));

Console.WriteLine(result);

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

C#
2,4,6

文字列のListでも同じです。

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

string result = string.Join(
", ",
names.Where(name => name.Contains("田"))
);

Console.WriteLine(result);

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

C#
田中

10-2. Selectで変換してからJoinする

Selectで値を変換してからstring.Joinする例です。

C#
List<int> ids = new List<int> { 1, 2, 3 };

string result = string.Join(",", ids.Select(id => $"ID:{id}"));

Console.WriteLine(result);

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

C#
ID:1,ID:2,ID:3

オブジェクトのListでもよく使います。

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

string result = string.Join(", ", users.Select(user => $"{user.Id}:{user.Name}"));

Console.WriteLine(result);

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

C#
1:田中, 2:佐藤

10-3. Distinctで重複を除いてJoinする

重複を除いてから結合したい場合は、Distinctを使います。

C#
List<string> tags = new List<string>
{
"C#",
"LINQ",
"C#",
".NET"
};

string result = string.Join(", ", tags.Distinct());

Console.WriteLine(result);

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

C#
C#, LINQ, .NET

ID一覧で重複を除きたい場合にも使えます。

C#
List<int> ids = new List<int> { 1, 2, 2, 3, 1 };

string result = string.Join(",", ids.Distinct());

Console.WriteLine(result);

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

C#
1,2,3

10-4. OrderByで並び替えてからJoinする

並び替えてから結合したい場合は、OrderByを使います。

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

string result = string.Join(",", numbers.OrderBy(n => n));

Console.WriteLine(result);

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

C#
1,2,3,4,5

降順にしたい場合は、OrderByDescendingを使います。

C#
string result = string.Join(",", numbers.OrderByDescending(n => n));

Console.WriteLine(result);

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

C#
5,4,3,2,1

オブジェクトのListを名前順に並び替えて結合することもできます。

C#
string result = string.Join(
", ",
users.OrderBy(user => user.Name)
.Select(user => user.Name)
);

Console.WriteLine(result);

WhereSelectDistinctOrderByを組み合わせると、実務で必要な文字列整形を簡潔に書けます。

11. 実務でよく使うstring.Joinのサンプル

string.Joinは、実務で非常によく使われるメソッドです。

ここでは、よくある利用シーンを具体的に紹介します。

11-1. ログ出力用に配列の中身を表示する

配列やListの中身をログに出したい場合、string.Joinが便利です。

C#
int[] ids = { 101, 102, 103 };

Console.WriteLine($"対象ID: {string.Join(",", ids)}");

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

C#
対象ID: 101,102,103

文字列のListでも同じです。

C#
List<string> errors = new List<string>
{
"Name is required",
"Email is invalid"
};

Console.WriteLine($"Errors: {string.Join(" | ", errors)}");

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

C#
Errors: Name is required | Email is invalid

ログでは、カンマ区切りだけでなく、" | "のような区切り文字も見やすくて便利です。

11-2. ID一覧をカンマ区切りで作る

データベース検索やAPI連携のために、ID一覧をカンマ区切りで作ることがあります。

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

string idList = string.Join(",", ids);

Console.WriteLine(idList);

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

C#
10,20,30

ただし、SQL文を直接組み立てる場合は注意が必要です。

C#
string sql = $"SELECT * FROM Users WHERE Id IN ({idList})";

このような文字列連結によるSQL組み立ては、SQLインジェクションや型変換の問題につながる可能性があります。

実際のデータベース処理では、できるだけパラメータ化されたクエリを使いましょう。

11-3. 画面表示用の名前リストを作る

ユーザー名や商品名の一覧を画面に表示する場合にも、string.Joinが便利です。

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

string displayText = string.Join("、", userNames);

Console.WriteLine(displayText);

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

C#
田中、佐藤、鈴木

日本語の文章では、カンマより読点の方が自然な場合があります。

C#
string message = $"参加者: {string.Join("", userNames)}";

Console.WriteLine(message);

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

C#
参加者: 田中、佐藤、鈴木

11-4. URLパラメータやメッセージ文を組み立てる

URLパラメータを組み立てるときにも、string.Joinを使うことがあります。

C#
List<string> parameters = new List<string>
{
"page=1",
"size=20",
"sort=name"
};

string queryString = string.Join("&", parameters);

Console.WriteLine(queryString);

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

C#
page=1&size=20&sort=name

URLに付ける場合は、次のようにできます。

C#
string url = "https://example.com/users?" + queryString;

Console.WriteLine(url);

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

C#
https://example.com/users?page=1&size=20&sort=name

ただし、実際のURLパラメータでは、値をURLエンコードする必要があります。

C#
var parameters = new Dictionary<string, string>
{
{ "keyword", "C# join" },
{ "sort", "name" }
};

string queryString = string.Join(
"&",
parameters.Select(p =>
$"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}")
);

Console.WriteLine(queryString);

このように、Selectkey=value形式に変換してからstring.Join("&", ...)で結合すると、URLクエリ文字列を作れます。

11-5. CSV出力で使う場合の注意点

CSV出力でもstring.Joinはよく使われます。

C#
string[] columns = { "Id", "Name", "Email" };

string header = string.Join(",", columns);

Console.WriteLine(header);

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

C#
Id,Name,Email

データ行を作る場合は、次のように書けます。

C#
var user = new User
{
Id = 1,
Name = "田中",
Email = "tanaka@example.com"
};

string line = string.Join(",", new[]
{
user.Id.ToString(),
user.Name,
user.Email
});

Console.WriteLine(line);

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

C#
1,田中,tanaka@example.com

ただし、CSVでは値の中にカンマや改行、ダブルクォーテーションが含まれる可能性があります。

そのため、実務でCSVファイルを出力する場合は、単純なstring.Joinだけでは不十分なことがあります。

簡易的に対応するなら、次のようなエスケープ処理を入れます。

C#
static string EscapeCsv(string value)
{
if (value.Contains(",") || value.Contains("\"") || value.Contains("\r") || value.Contains("\n"))
{
return $"\"{value.Replace("\"", "\"\"")}\"";
}

return value;
}

そして、次のように使います。

C#
string line = string.Join(",", new[]
{
EscapeCsv(user.Id.ToString()),
EscapeCsv(user.Name),
EscapeCsv(user.Email)
});

本格的なCSV出力では、専用ライブラリを使う方が安全です。

12. C# Joinに関するよくある質問

C#のJoinについて、よくある疑問をまとめます。

12-1. string.JoinとString.Concatの違いは?

string.Joinは、区切り文字を挟みながら複数の値を結合します。

C#
string[] values = { "A", "B", "C" };

string result = string.Join(",", values);

Console.WriteLine(result);

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

C#
A,B,C

一方、String.Concatは区切り文字なしで連結します。

C#
string[] values = { "A", "B", "C" };

string result = string.Concat(values);

Console.WriteLine(result);

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

C#
ABC

つまり、カンマやスペースなどの区切り文字を入れたい場合はstring.Join、単純につなげたいだけならString.Concatを使います。

12-2. Joinで最後のカンマを消す必要はある?

string.Joinを使う場合、最後のカンマを消す必要はありません。

C#
string[] values = { "A", "B", "C" };

string result = string.Join(",", values);

Console.WriteLine(result);

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

C#
A,B,C

最後にカンマは付きません。

手動でループ連結すると最後のカンマが問題になることがありますが、string.Joinなら自動で適切に区切ってくれます。

12-3. JoinでListの中身を1行で表示できる?

できます。

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

Console.WriteLine(string.Join(", ", names));

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

C#
田中, 佐藤, 鈴木

数値のListでも同じです。

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

Console.WriteLine(string.Join(",", numbers));

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

C#
1,2,3

12-4. Joinでnullや空文字を除外できる?

string.Join自体には、nullや空文字を自動で除外する機能はありません。

除外したい場合は、LINQのWhereを組み合わせます。

C#
string?[] values = { "A", null, "", "B", " " };

string result = string.Join(
",",
values.Where(value => !string.IsNullOrEmpty(value))
);

Console.WriteLine(result);

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

C#
A,B, 

空白だけの文字列も除外したい場合は、string.IsNullOrWhiteSpaceを使います。

C#
string?[] values = { "A", null, "", "B", " " };

string result = string.Join(
",",
values.Where(value => !string.IsNullOrWhiteSpace(value))
);

Console.WriteLine(result);

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

C#
A,B

12-5. Joinで複数の区切り文字を使える?

string.Joinで指定できる区切り文字は、基本的には1種類です。

C#
string result = string.Join(", ", values);

すべての要素の間に同じ区切り文字が入ります。

要素ごとに異なる区切り文字を使いたい場合は、string.Joinだけではなく、別のロジックを組み合わせる必要があります。

たとえば、「最後だけandでつなぐ」ような表示をしたい場合です。

C#
List<string> names = new List<string> { "Alice", "Bob", "Charlie" };

string result;

if (names.Count == 0)
{
result = "";
}
else if (names.Count == 1)
{
result = names[0];
}
else
{
result = string.Join(", ", names.Take(names.Count - 1))
+ " and "
+ names.Last();
}

Console.WriteLine(result);

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

C#
Alice, Bob and Charlie

このように、複数の区切りルールを使いたい場合は、条件分岐やLINQを組み合わせて整形します。

まとめ

C#のJoinには、主にstring.JoinとLINQのJoinという2つの意味があります。

配列やListの要素をカンマ区切りで1つの文字列にしたい場合は、string.Joinを使います。

C#
string[] values = { "A", "B", "C" };

string result = string.Join(",", values);

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

C#
A,B,C

List<string>List<int>も同じように結合できます。

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

string result = string.Join(", ", numbers);

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

C#
1, 2, 3

オブジェクトのListを結合したい場合は、Selectで必要なプロパティを取り出してからstring.Joinするのが基本です。

C#
string result = string.Join(", ", users.Select(user => user.Name));

一方、LINQのJoinは、文字列を結合するものではなく、2つのコレクションをキーで結合するためのメソッドです。

C#
var result = employees.Join(
departments,
employee => employee.DepartmentId,
department => department.Id,
(employee, department) => new
{
employee.Name,
DepartmentName = department.Name
}
);

「配列をカンマ区切りにしたい」「Listの中身を1行で表示したい」「ID一覧を文字列にしたい」という場合は、LINQのJoinではなくstring.Joinを使いましょう。

string.Joinは、最後の区切り文字を自動で調整してくれるため、ループで手動連結するよりも簡潔で読みやすいコードになります。配列、List、LINQの結果を文字列化する場面では、まずstring.Joinを使うことを検討するとよいでしょう。