Вот еще одна версия, которую я нашел здесь: http://www.reddit.com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1
Любое решение этой проблемы будет включать рефлексию, которая не идеальна, но вот его код с некоторыми другими основными проблемами производительности, которые были решены. (Без проверки ошибок. Добавьте, если хотите.):
1) Использует прямое отражение во время выполнения, без дополнительных затрат DataBinder
2) Не использует регулярные выражения, использует однопроходный анализ и состояние.
3) Не преобразовывает строку в промежуточную строку, а затем снова преобразовывает ее в окончательный формат.
4) Распределяет и объединяет с помощью одного StringBuilder, вместо того, чтобы обновлять строки повсеместно и объединять их в новые строки.
5) Удаляет затраты стека на вызов делегата для n операций замены.
6) В общем, это один проход, который будет масштабироваться относительно линейно (все же некоторая стоимость для каждого поиска и вложенного поиска, но это так.)
public static string FormatWith(this string format, object source)
{
StringBuilder sbResult = new StringBuilder(format.Length);
StringBuilder sbCurrentTerm = new StringBuilder();
char[] formatChars = format.ToCharArray();
bool inTerm = false;
object currentPropValue = source;
for (int i = 0; i < format.Length; i++)
{
if (formatChars[i] == '{')
inTerm = true;
else if (formatChars[i] == '}')
{
PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
sbResult.Append((string)(pi.PropertyType.GetMethod("ToString", new Type[]{}).Invoke(pi.GetValue(currentPropValue, null), null)));
sbCurrentTerm.Clear();
inTerm = false;
currentPropValue = source;
}
else if (inTerm)
{
if (formatChars[i] == '.')
{
PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
currentPropValue = pi.GetValue(source, null);
sbCurrentTerm.Clear();
}
else
sbCurrentTerm.Append(formatChars[i]);
}
else
sbResult.Append(formatChars[i]);
}
return sbResult.ToString();
}