You're bound to be unhappy if you optimize everything. --Donald Knuth

An Easier Way to Append Strings with a Delimiter

The Problem

One of the reasons I love coding is because I can do complex or tedious things once and then I never have to think about them again (well, that's the dream).

Appending strings is one of those annoying common tasks that you find yourself doing over and over again.

Below is a little solution for appending strings that I use surpisingly often. But let's first take a look at the problem.

Let's say you're creating a CSV file from some column-based data.

It might look something like this:

List<RowData> rows = GetRows();
StringBuilder sb = new StringBuilder();
foreach (RowData row in rows)
{
    sb.AppendLine(row.Field1 + ", " + row.Field2.ToString() + ", " + row.Field3.ToString());
}

string csv = sb.ToString();
return csv;

Now, that's pretty simple code right. But what if you don't know how many strings you have to append?

Then you can end up with something like this:

List<RowData> rows = GetRows();
StringBuilder sb = new StringBuilder();
foreach (RowData row in rows)
{
    for (int i = 0; i < row.Fields.Count; i++)
    {
        string field = row.Fields[i];
        if (i == rows.Count - 1)
        {
            sb.Append(field);
        }
        else
        {
            sb.Append(field + ", ");
        }
    }
    sb.Append(Environment.NewLine);
}

string csv = sb.ToString();
return csv;

In the above code, you now have to determine, "Is this the last field in the row?"

Because if it is last, then there should be no delimiter after it.

Things get even more complicated if you want to leave out empty strings.

The Solution

This solution will spare you a lot of annoyance and leave your braincells available for more pressing matters.

Add this simple StringBuilder extension to your code base.

You'll be surprised how often you end up using this.

StringBuilder.AppendDelim Extension Method
using System;
using System.Text;

namespace Cambia
{
    public static class StringBuilderExtensions
    {
        public static void AppendDelim(this StringBuilder sb, string text, string delim = ", ", bool writeEmptyString = true)
        {
            if (writeEmptyString || !String.IsNullOrWhiteSpace(text))
            {
                if (sb.Length != 0)
                {
                    sb.Append(delim + text);
                }
                else
                {
                    sb.Append(text);
                }
            }
        }
    }
}

Using this extension method, our first example becomes:

List<RowData> rows = GetRows();
StringBuilder sb = new StringBuilder();
foreach (RowData row in rows)
{
    sb.Append(row.Field1);
    sb.AppendDelim(row.Field2.ToString());
    sb.AppendDelim(row.Field3.ToString());
    sb.Append(Environment.NewLine);
}

string csv = sb.ToString();
return csv;

OK. You could argue that's not better really.

But this technique starts to shine in our second example.

List<RowData> rows = GetRows();
StringBuilder sb = new StringBuilder();
foreach (RowData row in rows)
{
   sb.Append(row.Fields[0]);
   for (int i=1; i<row.Fields.Count; i++)
   {
      sb.AppendDelim(field);
   }
   sb.Append(Environment.NewLine);
}

string csv = sb.ToString();
return csv;

Now that one is much simpler!

Trust me, you'll end up using this more than you think.

Other Ways of Joining Strings

There are a few other ways in the .NET framework that might also work for your situation.

// Static Join method on String
string s1 = String.Join(", ", "Bill", "Mary", "John", "Ricardo");
// Output: "Bill, Mary, John, Ricardo"

List<string> names = new List<string>() { "Bill", "Mary", "John", "Ricardo" };
string s2 = String.Join(", ", names);
// Output: "Bill, Mary, John, Ricardo"

// String.Format
string s3 = String.Format("{0} sat down. Then {1}, {2} and {3} arrived.", 
   "Bill", "Mary", "John", "Richard");
// Output: "Bill sat down. Then Mary, John and Ricardo arrived."

// String interpolation
string name1 = "Bill";
string name2 = "Mary";
string s3 = $"{name1} arrived, followed by {name2}.";
// Output: "Bill arrived, followed by Mary."
 

Version: 6.0.20200920.1535