Suppose I had a FormattableString like so:
var now = DateTime.Now;
FormattableString str = $"Today's date is: {now:yyyy-MM-dd} and some numbers: {new[]{1,2,3}}";
I'm trying to take a formattable string and transform it to be used in another component. In my case, essentially splitting the format string at the values so I can control how they're concatenated back, but I need the format string for the argument.
There are some limited methods on the FormattableString that allows me to get the argument values (GetArguments()/GetArgument()) and the original format string (Format), but there is none for accessing the argument formatting strings.
var format = str.Format; // "Today's date is: {0:yyyy-MM-dd} and some numbers: {1}"
var arguments = str.GetArguments(); // { now, new[]{1,2,3} }
// no simple way to get the "yyyy-MM-dd" part for arg 0
My workarounds I'm looking at are to preformat the value so the formatted value is set as the argument or parsing out the format string which would not be ideal.
void DumpLine(FormattableString format)
{
var values = format.GetArguments().Prepend(null);
var parts = Regex.Split(format.Format, @"\{[^}]+\}");
Util.HorizontalRun(false, values.Zip(parts).SelectMany(x => new[] { x.First, x.Second }).Skip(1)).Dump();
}
// usage
DumpLine($"Today's date is: {now.ToString("yyyy-MM-dd")} and some numbers: {new[]{1,2,3}}");
Is this supported, perhaps through a helper class or am I out of luck?
Thank you mariusz96 for pointing out the new InterpolatedStringHandler functionality. It does for me exactly what I needed it for. It's even flexible enough for me to add additional parameters should I need it in the future. This is what I ended up with:
public static class UtilEx
{
public static object Interpolate(IFormatProvider provider, [InterpolatedStringHandlerArgument(nameof(provider))] InterpolateFormatHandler handler) => Interpolate(handler);
public static object Interpolate(InterpolateFormatHandler handler) => Util.HorizontalRun(false, handler.Items);
[InterpolatedStringHandler]
public ref struct InterpolateFormatHandler
{
private readonly IFormatProvider? provider;
public InterpolateFormatHandler(int _literalLength, int _formattedCount, IFormatProvider? provider = default) => this.provider = provider;
public List<object?> Items { get; } = new();
public void AppendLiteral(string s) => Items.Add(s);
public void AppendFormatted<T>(T t, int alignment, string format) => Items.Add(string.Format(provider, $"{{0,{alignment}:{format}}}", t));
public void AppendFormatted<T>(T t, int alignment) => Items.Add(string.Format(provider, $"{{0,{alignment}}}", t));
public void AppendFormatted<T>(T t, string format) => Items.Add(string.Format(provider, $"{{0:{format}}}", t));
public void AppendFormatted<T>(T t) => Items.Add(t);
}
}
