In any programming language, it is very common to want to take something that is not a string (say a number) and turn it into a string. Perhaps you need to display it on the command-line, or in some sort of GUI, or when writing to a file (etc ...).
There are lots of different ways of turning .NET objects into a string, each with their own uses. I will try to show you as many as possible in this article.
All the examples will be in C#, because this is my blog and I can do what I like!
The ToString
method
Every object in .NET has a parameterless ToString
method (it is one of the few
methods on the System.Object
base class). By default it returns the fully
qualified name of the type
(source).
This is usually not very useful, so the ToString
method is virtual to allow
you to override it. When you implement any class in .NET, you can override
ToString
to do whatever you want.
Many of the built-in .NET types override this method to do something useful. For
example, all of the number types override ToString
to return a basically
formatted number. Here are a couple of examples:
Type | Example | Output |
---|---|---|
System.Int32 |
-123456 |
-123456 |
System.Decimal |
-1.23m |
-1.23 |
Standard format strings
Many types in .NET have another overload of the ToString
method, which allows
you to pass in what is known as a "format string". This format string specifies
how the object is to be formatted.
For example, if you call ToString
on a System.Decimal
with the format string
"e"
, it will format it using exponential notation (e.g. 0.000123m
would be
formatted as "1.23E-004"
).
The .NET documentation is pretty comprehensive when it comes to the standard format strings for numeric types and dates and times.
Custom format strings
The examples above are known as "standard" format strings, because they are
pre-defined to control the behaviour of the ToString
method. However,
sometimes it is useful to build up your own format strings from some pre-defined
building blocks. These are known as "custom" format strings.
A good example of this is the System.DateTime
struct, where there are many
building blocks, such as "d"
for the day of the month, "MMMM"
for the full
name of the month and "yyyy"
for the full year.
Taking var date = new System.DateTime(2019, 1, 2)
as an example, here are some
of the things you can do:
C# code | Output |
---|---|
date.ToString("dd MMM yyyy") |
02 Jan 2019 |
date.ToString("ddd d MMMM yyyy") |
Wed 2 January 2019 |
date.ToString("yyyy-MM-dd") |
2019-01-02 |
You'll notice that anything that is not recognised as a building block (such as a space or hyphen) is simply output verbatim.
Cultures
All of the examples that we've seen so far have used English for any words (e.g. day and month names). This is because my computer is set up to work with British English, and .NET respects that by default. There are other formatting options that are particular to different cultures around the world; for example, in Europe it is customary to use a comma as a decimal separator rather than a full stop.
Many .NET types allow you to pass an instance of IFormatProvider
to the
ToString
method which specifies how to deal with culture-specific formatting
requirements. The CultureInfo
class implements this interface, and uses the
standard .NET culture
specifiers.
Here are some DateTime
examples, using the same example of var date = new System.DateTime(2019, 1, 2)
:
C# code | Output |
---|---|
date.ToString("d", new CultureInfo("en-GB")) |
Wednesday, 2 January 2019 |
date.ToString("d", new CultureInfo("en-US")) |
Wednesday, January 2, 2019 |
date.ToString("d", new CultureInfo("fr-FR")) |
mercredi 2 janvier 2019 |
date.ToString("d", new CultureInfo("de-DE")) |
Mittwoch, 2. Januar 2019 |
You can use CultureInfo.CurrentCulture
to access the machine's
culture,
and Culture.InvariantCulture
to use a non-specific
culture.
It is usually best to specify the culture, especially if you are interacting with another system that expects a value in a particular format.
Composing strings
Suppose you want to compose a string from many different building blocks. There are a number of different ways of doing this, so let's take a look at these in turn.
For the following examples, let's take the following values:
var amount = 5;
var price = 1.2m;
var date = new System.DateTime(2019, 1, 2);
String concatenation
The simplest way to compose strings is by using the +
operator:
var output = "We sold " + amount.ToString() + " mars bars on " + date.ToString("D", new CultureInfo("en-US")) + ", each costing £" + price.ToString("N2") + ".";
This gives "We sold 5 mars bars on Wednesday, January 2, 2019, each costing £1.20."
.
You can omit the ToString
call if you like, and .NET will do an implicit cast
to string
, which is equivalent to calling ToString
with no arguments:
var output = "We sold " + amount + " mars bars on " + date + ", each costing £" + price + ".";
This gives "We sold 5 mars bars on 1/2/19 12:00:00 AM, each costing £1.2."
. As
you can see, this is not always desirable as you have no control over how the
strings are formatted.
The string.Format
method
The static method Format
on the System.String
class can be used to simplify
this. You give it a string containing placeholders and some objects, and the
method will format them and insert them into the placeholders.
It's best explained with an example:
var output = string.Format("We sold {0} mars bars on {1}, each costing £{2}.", amount, date, price);
This gives "We sold 5 mars bars on 1/2/19 12:00:00 AM, each costing £1.2."
, as
before. It has formatted the three objects by calling ToString
on them, and
inserted them into the placeholders using zero-based indexing.
You can also specify format strings, like so:
var output = string.Format("We sold {0} mars bars on {1:D}, each costing £{2:N2}.", amount, date, price);
This gives "We sold 5 mars bars on Wednesday, January 2, 2019, each costing £1.20."
.
If you want to specify the culture, you can do so by passing it as the first parameter. This will use the specified culture for every conversion in the string. See here for more info.
Methods using string.Format
implicitly
One of the overloads to Console.WriteLine
has the following definition:
public static void WriteLine(string format, params object[] arg)
. This works
the same way as the string.Format
method: you give it a format string
containing placeholders and some objects to be formatted and inserted.
There are a number of methods in the .NET framework and in third-party libraries that work this way, so watch out for them!
String interpolation
String interpolation is a feature that was introduced in C# 6, and it takes
the string.Format
method one step further. If you prepend a string with $
,
then anything inside curly braces gets formatted just like string.Format
. The
following gives identical output to the previous example.
var output = $"We sold {amount} mars bars on {date:D}, each costing £{price:N2}.";
This can make your code much more readable, so I'd advise using it where you need to compose strings!
See here for more information, including how to specify the culture.
Debugging
When debugging, you often want to see the property values of a particular
object. By default, the Visual Studio debug window will use the ToString
method to format the object so you can see its value.
You may be tempted to override ToString
to make debugging easier (remember,
the default implementation of ToString
simply returns the type name). Don't do
this! If you do, it is very easy for these string representations to find their
way into your production code. Instead, read this
article
to find out a better way of doing it using
System.Diagnostics.DebuggerDisplayAttribute
.
Summary
In this article we saw a number of ways of formatting strings in .NET:
- The
ToString
method (with or without format strings and culture specifiers) - The
string.Format
method - String interpolation
Let me know if you can think of any other ways of doing this!