Question
How can you create a comma-separated list of string values from an IList<string> or IEnumerable<string> in C#?
For example, suppose you have a collection of strings, but it is not stored as a string[]. You may have an IList<string> or an IEnumerable<string>, and converting it manually into an array just to call String.Join(...) can feel awkward.
What is the cleanest and most readable way to produce a single comma-separated string from such a collection?
Short Answer
By the end of this page, you will understand how to turn an IEnumerable<string> or IList<string> into a comma-separated string in C#. You will learn the idiomatic use of string.Join, how it works with collections, when conversion is unnecessary, and how to avoid common mistakes such as handling null values or adding separators manually.
Concept
In C#, a very common task is combining many string values into one string with a separator such as a comma, space, or pipe character.
The core concept here is joining a sequence of values into a single string.
If you have values like this:
var names = new List<string> { "Alice", "Bob", "Charlie" };
You often want this result:
"Alice,Bob,Charlie"
or this:
"Alice, Bob, Charlie"
In C#, the standard tool for this is string.Join.
A common beginner concern is that string.Join is only for arrays like string[]. That was a limitation in older usage patterns, but modern C# and .NET provide overloads that work directly with IEnumerable<string>.
That matters because many APIs return sequences such as:
List<string>IList<string>IEnumerable<string>
Mental Model
Think of string.Join like a machine that places glue between items in a line.
If your items are:
Alice Bob Charlie
and your glue is ", ", the machine produces:
Alice, Bob, Charlie
Important detail: the separator goes between items, not before the first one and not after the last one.
That is why string.Join is usually better than manually looping and appending commas yourself. It handles the separator placement for you.
Syntax and Examples
The basic syntax is:
string result = string.Join(separator, values);
Where:
separatoris a string such as", "valuesis a sequence of strings
Example with List<string>
using System;
using System.Collections.Generic;
var fruits = new List<string> { "Apple", "Banana", "Orange" };
string result = string.Join(", ", fruits);
Console.WriteLine(result);
Output:
Apple, Banana, Orange
Example with IEnumerable<string>
using System;
using System.Collections.Generic;
using System.Linq;
IEnumerable<> shortWords = [] { , , , }
.Where(word => word.Length <= );
result = .Join(, shortWords);
Console.WriteLine(result);
Step by Step Execution
Consider this code:
using System;
using System.Collections.Generic;
IEnumerable<string> names = new List<string> { "Ana", "Ben", "Cara" };
string result = string.Join(", ", names);
Console.WriteLine(result);
Here is what happens step by step:
-
namesis created as a sequence containing three strings:"Ana""Ben""Cara"
-
string.Join(", ", names)is called.- The separator is
", " - The values come from the
IEnumerable<string>sequence
- The separator is
-
string.Joinreads the sequence items in order. -
It builds one final string by putting the separator between each item:
- Start with
"Ana"
- Start with
Real World Use Cases
This pattern appears in many practical situations.
Displaying tags or labels
var tags = new List<string> { "csharp", "linq", "strings" };
string display = string.Join(", ", tags);
Useful for UI display such as:
csharp, linq, strings
Logging selected items
var selectedIds = new List<string> { "A12", "B34", "C56" };
logger.LogInformation("Selected items: {Items}", string.Join(", ", selectedIds));
Building query parameters or route pieces
var ids = new List<string> { "10", "20", "30" };
string csv = string.Join(",", ids);
That may be sent to an API as:
Real Codebase Usage
In real codebases, developers often use string.Join together with LINQ and validation.
Pattern: joining projected values
Sometimes the original collection contains objects, not strings.
var users = new[]
{
new { Name = "Ava" },
new { Name = "Noah" },
new { Name = "Liam" }
};
string names = string.Join(", ", users.Select(u => u.Name));
This is very common when formatting lists from domain objects.
Pattern: guard clause before joining
if (items == null)
{
return string.Empty;
}
return string.Join(", ", items);
This protects your code from a null collection reference.
Pattern: filtering empty values
var cleaned = values.Where(v => !string.IsNullOrWhiteSpace(v));
string result = string.Join(, cleaned);
Common Mistakes
1. Manually adding commas in a loop
Broken or awkward approach:
var result = "";
foreach (var item in items)
{
result += item + ",";
}
Problems:
- leaves a trailing comma
- less readable
- repeated string concatenation can be inefficient
Better:
string result = string.Join(",", items);
2. Assuming ToArray() is always required
Unnecessary code:
string result = string.Join(", ", items.ToArray());
If items is already an IEnumerable<string> and your framework supports the overload, this is usually unnecessary.
Better:
string result = string.Join(", ", items);
3. Forgetting to handle collections
Comparisons
| Approach | Example | Good for | Downsides |
|---|---|---|---|
string.Join | string.Join(", ", items) | Cleanly combining values with a separator | None for normal string-joining use |
| Manual loop + concatenation | result += item + ","; | Very simple demos | Trailing separators, less efficient, harder to read |
StringBuilder loop | Append items manually | Complex custom formatting | More code for a simple join |
Aggregate | items.Aggregate((a, b) => a + ", " + b) | Functional style experiments | Harder to read, can fail on empty sequences |
Cheat Sheet
// Best common solution
string result = string.Join(", ", values);
Common separators
string.Join(",", values); // A,B,C
string.Join(", ", values); // A, B, C
string.Join(" | ", values); // A | B | C
string.Join(Environment.NewLine, values); // one per line
With LINQ projection
string result = string.Join(", ", users.Select(u => u.Name));
Safe null handling
string result = string.Join(", ", values ?? Enumerable.Empty<string>());
Filter blanks first
string result = string.Join(", ", values.Where(v => !string.IsNullOrWhiteSpace(v)));
FAQ
Can string.Join work with IEnumerable<string> in C#?
Yes. In modern .NET, string.Join has overloads that work directly with IEnumerable<string>.
Do I need to convert a List<string> to an array before calling string.Join?
No, not usually. A List<string> can be passed directly to the appropriate overload.
What happens if one item in the collection is null?
That item is treated like an empty string in the output.
What happens if the whole collection is null?
You should guard against that case, for example with values ?? Enumerable.Empty<string>().
Is string.Join better than using a loop?
Yes for this task. It is shorter, clearer, and avoids separator-placement bugs.
Can I join values from objects instead of strings?
Yes. Use Select to project the property you want, then pass that sequence to string.Join.
Should I use instead of ?
Mini Project
Description
Build a small C# utility that formats a list of user-entered tags into a clean comma-separated string. This demonstrates how to join an IEnumerable<string>, remove blank entries, and produce user-friendly output that could be used in a console app, API, or admin tool.
Goal
Create a method that takes a sequence of strings, removes empty entries, and returns a clean comma-separated result.
Requirements
- Create a method that accepts an
IEnumerable<string>. - Ignore
null, empty, or whitespace-only values. - Return the remaining values as a comma-and-space separated string.
- Return an empty string if there are no valid values.
- Demonstrate the method with sample input in a console application.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Array Initialization Syntaxes Explained
Learn all common C# array initialization syntaxes with examples, rules, comparisons, and mistakes beginners often make.