考虑到这一点,我意识到我真正想要的是 String.Format() 将 IDictionary 作为参数,并且可以使用名称而不是索引来编写模板。
对于具有许多可能的键/值的字符串替换,索引号会导致难以辨认的字符串模板 - 在某些情况下,您甚至可能不知道哪些项目将有什么数字,所以我想出了以下扩展名:
https://gist.github.com/896724
基本上,这使您可以使用带有名称而不是数字的字符串模板和字典而不是数组,并让您拥有 String.Format() 的所有其他良好功能,如果需要,允许使用自定义 IFormatProvider,并允许使用所有常用的格式化语法——精度、长度等。
String.Format 参考资料中提供的示例是一个很好的示例,说明具有许多编号项目的模板如何变得完全难以辨认 - 将该示例移植到使用这种新的扩展方法,您会得到如下内容:
var replacements = new Dictionary<String, object>()
{
{ "date1", new DateTime(2009, 7, 1) },
{ "hiTime", new TimeSpan(14, 17, 32) },
{ "hiTemp", 62.1m },
{ "loTime", new TimeSpan(3, 16, 10) },
{ "loTemp", 54.8m }
};
var template =
"Temperature on {date1:d}:\n{hiTime,11}: {hiTemp} degrees (hi)\n{loTime,11}: {loTemp} degrees (lo)";
var result = template.Subtitute(replacements);
正如有人指出的那样,如果您正在编写的内容需要高度优化,请不要使用这样的东西 - 如果您必须以这种方式格式化数百万个字符串,在一个循环中,内存和性能开销可能会很大。
另一方面,如果您关心编写清晰、可维护的代码 - 并且如果您正在执行一系列数据库操作,从总体上看,此功能不会增加任何重大开销。
...
为方便起见,我确实尝试添加一个接受匿名对象而不是字典的方法:
public static String Substitute(this String template, object obj)
{
return Substitute(
template,
obj.GetType().GetProperties().ToDictionary(p => p.Name, p => p.GetValue(obj, null))
);
}
由于某种原因,这不起作用 - 将匿名对象传递new { name: "value" }
给该扩展方法会给出编译时错误消息,指出最佳匹配是该方法的 IDictionary 版本。不知道如何解决。(任何人?)