与版本一类似,不过这里没有动态构建正则表达式,因为有了中括号,很容易区分常量和变量,所以我们通过“属性名”来找“属性”(对应代码中第10行)。如果某个属性找不到,我们会将这“[Name]”原样返回(对就第17行)。另一种做法是抛出异常,我不建议抛异常,在ToString(string format)是不合乎“常理”的。
版本二相对版本一效率有很大提高,主要是因为版本二只使用一个简单的正则表达式:@"\[(?[^\]]+)\]"。而版本一中的如果被扩展类的属性特别多,动态生成的正则表达式会很长,执行起来也会相对慢。
我们现在来解决两个版本中都存在的时间日期格式问题,把时间日期格式"yyyy-MM-dd"也放入中括号中,测试代码如下:
People p3 = new People { Id = 1, Name = "鹤冲天", Brithday = new DateTime(1990, 9, 9) };
string s3 = p3.ToString3("People:Id [Id: d4], Name [Name], Brithday [Brithday: yyyy-MM-dd]");
string s3 = p3.ToString3("People:Id [Id: d4], Name [Name], Brithday [Brithday: yyyy-MM-dd]");
版本三实现代码:
public static string ToString3(this object obj, string format)
{
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties(
BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance);
MatchEvaluator evaluator = match =>
{
string propertyName = match.Groups["Name"].Value;
string propertyFormat = match.Groups["Format"].Value;
PropertyInfo propertyInfo = properties.FirstOrDefault(p => p.Name == propertyName);
if (propertyInfo != null)
{
object propertyValue = propertyInfo.GetValue(obj, null);
if (string.IsNullOrEmpty(propertyFormat) == false)
return string.Format("{0:" + propertyFormat + "}", propertyValue);
else return propertyValue.ToString();
}
else return match.Value;
};
string pattern = @"\[(?[^\[\]:]+)(\s*:\s*(?[^\[\]:]+))?\]";
return Regex.Replace(format, pattern, evaluator, RegexOptions.Compiled);
}
{
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties(
BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance);
MatchEvaluator evaluator = match =>
{
string propertyName = match.Groups["Name"].Value;
string propertyFormat = match.Groups["Format"].Value;
PropertyInfo propertyInfo = properties.FirstOrDefault(p => p.Name == propertyName);
if (propertyInfo != null)
{
object propertyValue = propertyInfo.GetValue(obj, null);
if (string.IsNullOrEmpty(propertyFormat) == false)
return string.Format("{0:" + propertyFormat + "}", propertyValue);
else return propertyValue.ToString();
}
else return match.Value;
};
string pattern = @"\[(?[^\[\]:]+)(\s*:\s*(?[^\[\]:]+))?\]";
return Regex.Replace(format, pattern, evaluator, RegexOptions.Compiled);
}
测试一下,可OK了: