Mechanisms for formatting strings are many and various in C#/.NET: everything from simple concatenation of objects through calls to the overridden object.ToString()
method to use of ICustomFormatter
(not covered in this exercise).
The two most common mechanisms for formatting strings are string interpolation and String.Format(). The StringBuilder
(cross-ref-tba) class can also be used to build up a string if there is complexity such as multiple lines involved.
ToString()
System.Object()
from which all classes and structs inherit has a ToString()
method. For example new DateTime(2019, 5, 23).ToString()
will render "05/23/2019 00:00:00" (on a thread with US culture - see below). There are situations such as string concatenation where this default ToString()
method may be invoked implicitly, "" + new DateTime(2019, 5, 23)
gives the same result.
In addition to the default ToString()
method, types where formatting is an issue will have overloads which take a format string or even a format provider. Notably in the BCL (Base Class Library) these are numbers, dates, enums and GUIDs.
String.Format()
takes a string (referred to in the documentation as a composite format) comprising fixed text and placeholders (known in the documentation as a format items) and a variable number of arguments. The return value resolves each format item using the corresponding argument and combines the resolved values with the fixed text.
string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25))
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
Format()
may be a better choice than interpolation where the format is being used in multiple expressions as a kind of template or where incorporating the format, and the expressions to be formatted is too cumbersome such as when [verbatim strings][verbatim-strings] are involved.
This mechanism is technically known as composite formatting.
A fuller list of string producing methods that take advantage composite formatting is given in this article.
Interpolated strings are prefixed with a $
and include run-time expressions enclosed in braces. The format item has the following syntax: $"{<interpolationExpression>[,<alignment>][:<formatString>]}"
. They do away with the need for a separate list of arguments. The result is functionally equivalent to the String.Format()
mechanism.
The expression can comprise anything in scope. Alignment is the length of the "field" in which the text sits. If the alignment is positive then the text is padded with spaces on the left and if it is negative then the padding is to the right of the text.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a format item.
A format item can comprise up to 3 parts. The first is the mandatory expression or argument placeholder as seen in the example code above. In addition, there is an optional alignment (introduced with a comma, ",") and an optional format string (introduced with a colon, ":").
{<interpolationExpression>[,<alignment>][:<formatString>]}
The alignment specifies the length of the "field" in which the text is placed, padded to the left with spaces if the alignment is positive or to the right if it is negative.
The format string specifies the shape of the text output such as whether thousands separators should be included for a number or whether the date part only of a DateTime
object should be output.
The following code illustrates display of the date portion of a DateTime
object and a floating-point number in exponential form.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password."
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
string.Format(
"I had {0:E} bitcoins on {1:d}, the day I forgot my password.",
loadsOf, thatDay)
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
There is both standard and custom formatting for both numbers and dates. There is no vital difference between custom and standard except that you have a chance to compose custom format strings out of format characters. "custom" in this context has nothing to do with the ICustomFormatter
interface which is used when developing your own custom formatters.
The Base Class Library (BCL) provides 2 formatters: DateTimeFormatInfo
and NumberFormatInfo
and 6 groups of format strings.
The various lists of format strings are below:
Enum
and GUID
format strings can be classed as standard. Although enum
and GUID
have ToString()
overloads that take an IFormatProvider
it is not clear that it does anything.
An attempt is made in the library to instill some consistency into format strings (beyond the fact that they are represented as strings). This push for consistency is found in the standard strings. In reality as a developer you rarely care about the difference between standard and custom strings. Although it is a good idea, if you are implementing formatters for your own classes to echo the existing standard strings if your classes appear to call for it, you can pretty well ignore the difference.
Each thread of execution has a default culture Thread.CurrentThread.CurrentCulture
encapsulated in an instance of CultureInfo
. The thread's culture determines how dates and numbers are formatted by default with respect to regional variations such as the difference in conventional date format between the UK DD/MM/YYYY and the US MM/DD/YYYY.
CultureInfo
implements the IFormatProvider
interface which can be passed to certain overloads of String.Format()
. This can be used to override the thread culture.