I'd like you to think back. Back to when you started developing. It doesn't have to be in any particular language, just when you started learning. If you're like me (and I hope you are, otherwise this opening is a bit of a waste), then one of the first things you'll have learnt is how to work with strings. More specifically, how you'd do this:
Console.WriteLine("What is your name?");
var name = Console.ReadLine();
Console.WriteLine("Hello, " + name + ".");
However, once you start dealing with large sets of data you want to convey in a string, things start getting funky. Below is an example of a method that takes some cats that are up for adoption, along with the currency code and the cost of each cat and returns a nice, human-readable string:
public string GenerateCatAdoptionList(IEnumerable<string> cats, char currencySymbol, double costPerCat)
{
string catMessage = "The cats looking for loving homes are: " + cats.First();
foreach (var cat in cats)
{
if (cat == cats.Last())
{
catMessage += " and " + cat + ".";
}
else if (cat != cats.First())
{
catMessage += ", " + cat;
}
}
catMessage += " Our adoption fee is " + currencySymbol + costPerCat;
return catMessage;
}
Running this will return the following string:
The cats looking for loving homes are: Pickles, Larry, Mr Meow, Matilda and Ace. Our adoption fee is £200
Good question, person who read that out load. Interpolation does have a place in the world and is definitely something that could be used in this example:
public string GenerateCatAdoptionList(IEnumerable<string> cats, char currencySymbol, double costPerCat)
{
string catMessage = "The cats looking for loving homes are: " + cats.First();
string catMessage = $"The cats looking for loving homes are: {cats.First()}";
foreach (var cat in cats)
{
if (cat == cats.Last())
{
catMessage += " and " + cat + ".";
catMessage += $" and {cat}.";
}
else if (cat != cats.First())
{
catMessage += ", " + cat;
catMessage += $", {cat}";
}
}
catMessage += " Our adoption fee is " + currencySymbol + costPerCat;
catMessage += $" Our adoption fee is {currencySymbol}{costPerCat}";
return catMessage;
}
Yep, that is a bit better, isn't it. But is there another way?
The class StringBuilder is a great way to build up strings (shocking, I know). I like to use it if I'm going to be building up a string (again, shocking) as, unlike a string, StringBuilder is lets you manipulate, add to and replace data in a representation of a string without creating a new string. That's right, string is immutable, so every time you alter one of them, you are in fact creating a new one.
Now, this doesn't mean you should always use a StringBuilder. A lot of the time, a spot of interpolation be just the ticket. Where it really shines is when you are dealing with large datasets, such as a list of cats that you want to herd into a string. On that poor segue, let's take a look at our code re-written to use StringBuilder.
public string GenerateCatAdoptionList(IEnumerable<string> cats, char currencySymbol, double costPerCat)
{
string catMessage = $"The cats looking for loving homes are: {cats.First()}";
StringBuilder catMessage = new StringBuilder($"The cats looking for loving homes are: {cats.First()}");
foreach (var cat in cats)
{
if (cat == cats.Last())
{
catMessage += $" and {cat}.";
catMessage.Append($" and {cat}.");
}
else if (cat != cats.First())
{
catMessage += $", {cat}";
catMessage.Append($", {cat}");
}
}
catMessage += $" Our adoption fee is {currencySymbol}{costPerCat}";
catMessage.Append($" Our adoption fee is {currencySymbol}{costPerCat}");
return catMessage
return catMessage.ToString();
}
Now that we have done that, we can start using some of the advanced functionality of StringBuilder. Let's say you want to the adoption fee to appear on a different line to the cats. For that, you actually need to modify the last cat statement:
...
catMessage.Append($" and {cat}.");
catMessage.AppendLine($" and {cat}.");
...
AppendLine adds the string you have passed in and then adds a newline character.
One last thing. When I'm using interpolation, I have a rule:
Using this rule, the line adding the fees becomes:
...
catMessage.Append($"Our adoption fee is {currencySymbol}{costPerCat}");
catMessage.AppendFormat("Our adoption fee is {0}{1}", currencySymbol, costPerCat);
...
AppendFormat is, unsurprisingly, the equivalent to string.Format
. I've no evidence to back this up, but I think it reads much nicer.
Now, all being well, we should have only made one change to the output of our method. Shall we take a look at the finished product?
public string GenerateCatAdoptionList(IEnumerable<string> cats, char currencySymbol, double costPerCat)
{
StringBuilder catMessage = new StringBuilder($"The cats looking for loving homes are: {cats.First()}");
foreach (var cat in cats)
{
if (cat == cats.Last())
{
catMessage.Append($" and {cat}.");
}
else if (cat != cats.First())
{
catMessage.AppendLine($" and {cat}.");
}
}
catMessage.AppendFormat("Our adoption fee is {0}{1}", currencySymbol, costPerCat);
return catMessage.ToString();
}
The cats looking for loving homes are: Pickles, Larry, Mr Meow, Matilda and Ace.
Our adoption fee is £200
Hooray!