String Formatting in C#

Our program demonstrates various string formatting techniques in C#. Here’s the full source code:

using System;

public class StringFormatting
{
    public struct Point
    {
        public int X, Y;
        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }
    }

    public static void Main()
    {
        // C# offers several formatting options for various data types.
        // Here's an example with our Point struct.
        var p = new Point(1, 2);
        Console.WriteLine($"struct1: {p}");

        // To include the field names, we can use string interpolation
        // with the object's properties.
        Console.WriteLine($"struct2: {{X:{p.X}, Y:{p.Y}}}");

        // For a representation similar to source code, we can create a custom string.
        Console.WriteLine($"struct3: new Point({p.X}, {p.Y})");

        // To print the type of a value, use GetType().
        Console.WriteLine($"type: {p.GetType()}");

        // Formatting booleans is straightforward.
        Console.WriteLine($"bool: {true}");

        // There are many options for formatting integers.
        // Use D for standard, base-10 formatting.
        Console.WriteLine($"int: {123:D}");

        // This prints a binary representation.
        Console.WriteLine($"bin: {14:B}");

        // This prints the character corresponding to the given integer.
        Console.WriteLine($"char: {(char)33}");

        // X provides hexadecimal encoding.
        Console.WriteLine($"hex: {456:X}");

        // There are also several formatting options for floats.
        // For basic decimal formatting use F.
        Console.WriteLine($"float1: {78.9:F}");

        // E formats the float in scientific notation.
        Console.WriteLine($"float2: {123400000.0:E}");

        // For basic string printing, no special format is needed.
        Console.WriteLine($"str1: {"\"string\""}");

        // To print a verbatim string, use the @ symbol.
        Console.WriteLine($"str2: {@"""string"""}");

        // To print a hexadecimal representation of a string, we need to convert it manually.
        Console.WriteLine($"str3: {BitConverter.ToString("hex this"u8.ToArray()).Replace("-", "")}");

        // To print a representation of a pointer, use the address of operator &.
        unsafe
        {
            fixed (int* ptr = &p.X)
            {
                Console.WriteLine($"pointer: {(IntPtr)ptr:X}");
            }
        }

        // When formatting numbers you will often want to control the width and precision.
        // To specify the width of an integer, use a number after the colon.
        Console.WriteLine($"width1: |{12,6}|{345,6}|");

        // You can also specify the width and precision of printed floats.
        Console.WriteLine($"width2: |{1.2,6:F2}|{3.45,6:F2}|");

        // To left-justify, use a negative width.
        Console.WriteLine($"width3: |{1.2,-6:F2}|{3.45,-6:F2}|");

        // You may also want to control width when formatting strings.
        Console.WriteLine($"width4: |{"foo",6}|{"b",6}|");

        // To left-justify strings, use a negative width.
        Console.WriteLine($"width5: |{"foo",-6}|{"b",-6}|");

        // String.Format can be used to format and return a string without printing it.
        string s = string.Format("sprintf: a {0}", "string");
        Console.WriteLine(s);

        // You can format and write to TextWriters other than Console.Out using Write or WriteLine.
        Console.Error.WriteLine($"io: an {"error"}");
    }
}

To run the program, compile the code and use dotnet run:

$ dotnet run
struct1: StringFormatting+Point
struct2: {X:1, Y:2}
struct3: new Point(1, 2)
type: StringFormatting+Point
bool: True
int: 123
bin: 1110
char: !
hex: 1C8
float1: 78.90
float2: 1.234000E+008
str1: "string"
str2: "string"
str3: 6865782074686973
pointer: 7FFF1234ABCD
width1: |    12|   345|
width2: |  1.20|  3.45|
width3: |1.20  |3.45  |
width4: |   foo|     b|
width5: |foo   |b     |
sprintf: a string
io: an error

This C# program demonstrates various string formatting techniques, including formatting for different data types, controlling width and precision, and writing to different output streams. The concepts are similar to the original Go example, but adapted to C#’s syntax and standard library.