Skip to content

Instantly share code, notes, and snippets.

@pmunin
Last active May 29, 2019 00:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmunin/5cb1d6e388bb1efd2e2479383e3cafa4 to your computer and use it in GitHub Desktop.
Save pmunin/5cb1d6e388bb1efd2e2479383e3cafa4 to your computer and use it in GitHub Desktop.
FormattableStringExtensions C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace FormattableStrings
{
public static class FormattableStringExtensions
{
class Formattable : IFormattable
{
public Formattable(Func<(string format, IFormatProvider provider, Formattable formattable), string> toStringFunc)
{
this.ToStringFunc = toStringFunc;
}
public Func<(string format, IFormatProvider provider, Formattable formattable), string> ToStringFunc;
public string ToString(string format, IFormatProvider formatProvider)
{
return ToStringFunc((format, formatProvider, this));
}
}
/// <summary>
/// Converts formattable string to regular string, allowing to substitute its formattable parameters with any other value
/// for example FormatArgs($"Value A:{1}, B:{2}", arg=>(int)arg.value+1) will return Value A:2, B:3
/// </summary>
/// <param name="str"></param>
/// <param name="getParamValue"></param>
/// <returns></returns>
public static string FormatArgs(this FormattableString str, Func<(object value, int index, string format, IFormatProvider formatProvider), object> getParamValue)
{
var args = str.GetArguments().Select((val, i) =>
new Formattable(p=> {
var r = getParamValue((val, i, p.format, p.provider));
if (r is string s) return s;
if (r is IFormattable f) return f.ToString(p.format, p.provider);
return r.ToString();
})
).ToArray();
return string.Format(str.Format, args: args);
}
public static FormattableString ReformatArgs(this FormattableString str, Func<(object value, int index, string format, IFormatProvider formatProvider), object> getParamValue)
{
var args = str.GetArguments().Select((val, i) =>
new Formattable(p => {
var r = getParamValue((val, i, p.format, p.provider));
if (r is string s) return s;
if (r is IFormattable f) return f.ToString(p.format, p.provider);
return r.ToString();
})
).ToArray();
return FormattableStringFactory.Create(str.Format, arguments: args);
}
/// <summary>
/// Generates string allowing to substitute each parameter, extracting properties from it.
/// E.g.: FormatArgsByProperties($"My object: {new {Prop1=123}}", arg=>{var kvp = arg.properties.First(); return kvp.Key"="+kvp.Value.value.ToString()}) will return "My object: Prop1=123"
/// </summary>
/// <param name="str"></param>
/// <param name="getValue"></param>
/// <returns></returns>
public static string FormatArgsByProperties(this FormattableString str,
Func<(Dictionary<string, (PropertyInfo property, object value)> properties, int index), object> getValue)
{
return str.FormatArgs(arg =>
{
var props = arg.value?.GetType()?.GetProperties();
var dict = props?.ToDictionary(p => p.Name, p => (property: p, value: p.GetValue(arg)));
return getValue((dict, arg.index));
});
}
public static string FormatArgsByFirstProperty(this FormattableString str,
Func<(PropertyInfo property, object value, int index), object> getValue)
{
return str.FormatArgs(arg =>
{
var prop = arg.value?.GetType()?.GetProperties()?.FirstOrDefault();
return getValue((prop, prop?.GetValue(arg.value), arg.index));
});
}
public static FormattableString AppendFormattable(this FormattableString str, FormattableString str2)
{
var arg2Start = str.GetArguments().Length;
var fmt2 = str2.FormatArgs(arg =>
{
var res = $"{arg.index+arg2Start}" + (arg.format != null ? $":{arg.format}" : "");
res = "{" + res + "}";
return res;
});
return FormattableStringFactory.Create(str.Format + fmt2, arguments: str.GetArguments().Concat(str2.GetArguments()).ToArray());
}
public static FormattableString AppendFormattable(this string str, FormattableString str2)
{
var fmt = str + str2.Format;
var args = str2.GetArguments();
return System.Runtime.CompilerServices.FormattableStringFactory.Create(fmt, args);
}
public static FormattableString AsFormattable(this string str)
{
return FormattableStringFactory.Create(str);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment