[InterpolatedStringHandler]
public readonly ref struct EmbeddedClientStreamInterpolatedStringHandler {
readonly List<(bool WasDynamicElement, Memory<byte> EncodedData)> _data;
public EmbeddedClientStreamInterpolatedStringHandler(int literalLength, int formattedCount) {
// literalLength is the sum total length of all the literal 'sections' of the interpolated string
// formattedCount is the number of non-literal components to the string (i.e. the number of elements demarcated with {} braces)
// I'm not going to use either of them here
_data = new();
}
public void AppendLiteral(string s) { // This method is called to append a section of the literal (non-interpolated) part of the string
_data.Add((false, Encoding.UTF8.GetBytes(s)));
}
public void AppendFormatted<T>(T obj) { // This method is called to append a dynamic object (i.e. an element enclosed in {} braces)
_data.Add((true, Encoding.UTF8.GetBytes(obj?.ToString() ?? "")));
}
public void AppendFormatted<T>(T obj, string format) where T : IFormattable { // This method is called to append a dynamic object with a format string
_data.Add((true, Encoding.UTF8.GetBytes(obj?.ToString(format, null) ?? "")));
}
public void AppendFormatted(byte[] obj) { // You can even supply specific methods for handling specific types
AppendFormatted(String.Join(null, obj.Select(b => b.ToString("x2"))));
}
public string GetFormattedText() {
var totalLength = _data.Sum(tuple => tuple.EncodedData.Length);
// Note: There's a more efficient way to do this; we could pre-calculate this as the data comes in.
// But it's a blog post about InterpolatedStringHandlers, not efficient algorithms, and I'm tired ;).
// And this will be at the bottom of the post where no one gets to anyway. Prove me wrong by leaving a comment!
while (totalLength > EmbeddedClientStream.MaxMessageLength && _data.Count > 0) {
var lastStaticElementIndex = -1;
totalLength = 0;
for (var i = _data.Count - 1; i >= 0; --i) {
if (lastStaticElementIndex > 0 || _data[i].WasDynamicElement) totalLength += _data[i].EncodedData.Length;
else lastStaticElementIndex = i;
}
_data.RemoveAt(lastStaticElementIndex > -1 ? lastStaticElementIndex : _data.Count - 1);
}
return String.Join(null, _data.Select(tuple => Encoding.UTF8.GetString(tuple.EncodedData.Span)));
}
}
Code snippet taken from "Complete C# Quick Reference - C# 10".