C# -

Interpolated String Handlers

Interpolated String Handlers are a feature introduced in C# 10.0 that provide a way to optimize string interpolation by allowing developers to define custom handlers for interpolated strings. This tutorial will cover the basics of interpolated string handlers, their usage, best practices, and more, with comparisons to previous methods.


1. Introduction to Interpolated String Handlers

Interpolated String Handlers provide a way to customize the behavior of interpolated strings. This can be used to improve performance and add custom formatting logic.


2. Basic Usage

Here's a basic example of using an interpolated string handler:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine($"Hello, World!");
    }
}
        
    

3. Comparison with Previous Methods

Before C# 10, string interpolation was done directly. Here's how it compares:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        string name = "Alice";
        int age = 30;

        // Before C# 10
        string oldWay = string.Format("Name: {0}, Age: {1}", name, age);
        Console.WriteLine(oldWay);

        // C# 10 with Interpolated String Handlers
        string newWay = $"Name: {name}, Age: {age}";
        Console.WriteLine(newWay);
    }
}
        
    

4. Custom Interpolated String Handlers

You can create custom interpolated string handlers to customize how interpolation is done. Here's an example:

        
            using System;
using System.Text;

namespace InterpolatedStringHandlersExamples;

public class CustomHandler
{
    private readonly StringBuilder _builder = new StringBuilder();

    public CustomHandler(int literalLength, int formattedCount) { }

    public void AppendLiteral(string s) => _builder.Append(s);
    public void AppendFormatted<T>(T t) => _builder.Append($"[{t}]");

    public override string ToString() => _builder.ToString();
}

public class Program
{
    public static void Main(string[] args)
    {
        CustomHandler handler = new(0, 0);
        Console.WriteLine(handler.ToString());
    }
}
        
    

5. Using Handlers for Logging

Interpolated string handlers can be very useful for logging. Here's how:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Logger
{
    public void Log(string message) => Console.WriteLine(message);

    public void LogInterpolatedHandler([InterpolatedStringHandlerArgument("")] LogInterpolatedStringHandler handler)
    {
        if (handler.IsEnabled)
        {
            Log(handler.ToString());
        }
    }
}

public ref struct LogInterpolatedStringHandler
{
    private readonly StringBuilder _builder;
    public bool IsEnabled { get; }

    public LogInterpolatedStringHandler(int literalLength, int formattedCount, Logger logger, out bool isEnabled)
    {
        _builder = new StringBuilder(literalLength);
        IsEnabled = isEnabled = true;
    }

    public void AppendLiteral(string s) => _builder.Append(s);
    public void AppendFormatted<T>(T t) => _builder.Append(t);

    public override string ToString() => _builder.ToString();
}

public class Program
{
    public static void Main(string[] args)
    {
        var logger = new Logger();
        logger.LogInterpolatedHandler($"This is a log message with an interpolated value: {42}");
    }
}
        
    

6. Performance Considerations

Interpolated string handlers can improve performance by reducing allocations. Here's a performance comparison:

        
            using System;
using System.Diagnostics;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < 1000000; i++)
        {
            string s = $"Iteration {i}";
        }
        stopwatch.Stop();
        Console.WriteLine($"Elapsed time: {stopwatch.ElapsedMilliseconds}ms");
    }
}
        
    

7. Complex Interpolated Strings

Handling complex interpolated strings can be simplified with handlers. Here's an example:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        var person = new { Name = "Alice", Age = 30 };
        string s = $"Name: {person.Name}, Age: {person.Age}";
        Console.WriteLine(s);
    }
}
        
    

8. Formatting with Interpolated String Handlers

Custom formatting can be achieved with interpolated string handlers. Here's how:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        DateTime date = DateTime.Now;
        string formatted = $"Today is {date:dddd, MMMM d, yyyy}";
        Console.WriteLine(formatted);
    }
}
        
    

9. Handling Null and Empty Values

Interpolated string handlers can handle null and empty values more gracefully. Here's an example:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        string name = null;
        string s = $"Name: {name ?? "Unknown"}";
        Console.WriteLine(s);
    }
}
        
    

10. Combining Interpolated String Handlers with Other Features

Interpolated string handlers can be combined with other C# features for more powerful code. Here's an example:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        var person = new { Name = "Alice", Age = 30 };
        string s = person switch
        {
            { Age: > 18 } => $"Adult: {person.Name}",
            _ => $"Minor: {person.Name}"
        };
        Console.WriteLine(s);
    }
}
        
    

11. Best Practices for Using Interpolated String Handlers

Here are some best practices to follow when using interpolated string handlers:


12. Practical Use Cases

Interpolated string handlers can be used in various practical scenarios. Here are some examples:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        decimal price = 123.45m;
        string s = $"The price is {price:C}";
        Console.WriteLine(s);
    }
}
        
    

13. Future Enhancements

As C# evolves, interpolated string handlers may see further enhancements. Here's what to look forward to:

        
            using System;

namespace InterpolatedStringHandlersExamples;

public class Program
{
    public static void Main(string[] args)
    {
        // Example of potential future enhancements (hypothetical)
        string s = $"This is a future enhancement example";
        Console.WriteLine(s);
    }
}
        
    


14. Conclusion

Interpolated string handlers in C# provide a powerful tool for optimizing and customizing string interpolation. By following best practices and understanding their capabilities, you can effectively use interpolated string handlers to improve your code.