大家使用String.Format需要注意的一下性能问题。
以前的我总是觉得String.Format用起来非常方便,比+号拼接好多了,久而久之就习惯了用String.Format
这种方式去拼接字符串。今天闲来无聊,就具体得了解了一下String.Format。我这里使用的是反编译工具(Reflector),那么现在就一起去探索一下String.Format这个方法吧。
通过反编译工具查看之后,首先进入我们眼前的是如下代码:
public static string Format(IFormatProvider provider, string format, params object[] args)
{
if ((format == null) || (args == null))
{
throw new ArgumentNullException((format == null) ? "format" : "args");
}
StringBuilder sb = StringBuilderCache.Acquire(format.Length + (args.Length * 8));
sb.AppendFormat(provider, format, args);
return StringBuilderCache.GetStringAndRelease(sb);
}
我们通过上面的代码可以看出,微软是通过StringBuilder来处理的Format,看到这里,我内心默念了一句,我靠,一直在用sting这个类,里面居然封装的StringBuilder,瞬间感觉微软欺骗我纯洁的内心。好了,咱们继续往下走,既然是使用的是StringBuilder,那么问题来了,他的初始化容量是如何得到的呢? 看到微软的代码:
format.Length + (args.Length * 8)
看上面这个计算公式,我们可以得出结论,根据这个数组的个数(args)去乘以8,然后再加上字符的个数(format) 的长度, 来初始化StringBuilder的容量,那么这样是否就可以了呢?性能上面真的可以吗?
那么问题来了,这个数组(args)的个数是乘以8就相当于每一个数组中的元
素的最大长度只能有8位,如果超过了呢?那么StringBuilder就得扩容啦。
那么这里我就建议大家直接使用StringBuilder吧,这样的话就自己设置容量,
这样就可以把性能掌握在自己手中啦!
2、再来看看里面还有啥?
下面还有一句:
sb.AppendFormat(provider, format, args);
那么这句是干什么的呢? 大家也许根据方法名就可以解读啦。追加格式化的意思。那么博主我的好奇心又来了, 他到底是如何格式化字符串的呢?微软到底是如何写的?于是我进入这个方法:
public StringBuilder AppendFormat(IFormatProvider provider, string format, params object[] args)
{
if ((format == null) || (args == null))
{
throw new ArgumentNullException((format == null) ? "format" : "args");
}
int num = 0;
int length = format.Length;
char ch = '\0';
ICustomFormatter formatter = null;
if (provider != null)
{
formatter = (ICustomFormatter) provider.GetFormat(typeof(ICustomFormatter));
}
Label_0096:
while (num < length)
{
ch = format[num];
num++;
if (ch == '}')
{
if ((num < length) && (format[num] == '}'))
{
num++;
}
else
{
FormatError();
}
}
if (ch == '{')
{
if ((num < length) && (format[num] == '{'))
{
num++;
}
else
{
num--;
break;
}
}
this.Append(ch);
}
if (num == length)
{
return this;
}
num++;
if (((num == length) || ((ch = format[num]) < '0')) || (ch > '9'))
{
FormatError();
}
int index = 0;
do
{
index = ((index * 10) + ch) - 0x30;
num++;
if (num == length)
{
FormatError();
}
ch = format[num];
}
while (((ch >= '0') && (ch <= '9')) && (index < 0xf4240));
if (index >= args.Length)
{
throw new FormatException(Environment.GetResourceString("Format_IndexOutOfRange"));
}
while ((num < length) && ((ch = format[num]) == ' '))
{
num++;
}
bool flag = false;
int num4 = 0;
if (ch == ',')
{
num++;
while ((num < length) && (format[num] == ' '))
{
num++;
}
if (num == length)
{
FormatError();
}
ch = format[num];
if (ch == '-')
{
flag = true;
num++;
if (num == length)
{
FormatError();
}
ch = format[num];
}
if ((ch < '0') || (ch > '9'))
{
FormatError();
}
do
{
num4 = ((num4 * 10) + ch) - 0x30;
num++;
if (num == length)
{
FormatError();
}
ch = format[num];
}
while (((ch >= '0') && (ch <= '9')) && (num4 < 0xf4240));
}
while ((num < length) && ((ch = format[num]) == ' '))
{
num++;
}
object arg = args[index];
StringBuilder builder = null;
if (ch == ':')
{
num++;
while (true)
{
if (num == length)
{
FormatError();
}
ch = format[num];
num++;
switch (ch)
{
case '{':
if ((num < length) && (format[num] == '{'))
{
num++;
}
else
{
FormatError();
}
break;
case '}':
if ((num < length) && (format[num] == '}'))
{
num++;
}
else
{
num--;
goto Label_0250;
}
break;
}
if (builder == null)
{
builder = new StringBuilder();
}
builder.Append(ch);
}
}
Label_0250:
if (ch != '}')
{
FormatError();
}
num++;
string str = null;
string str2 = null;
if (formatter != null)
{
if (builder != null)
{
str = builder.ToString();
}
str2 = formatter.Format(str, arg, provider);
}
if (str2 == null)
{
IFormattable formattable = arg as IFormattable;
if (formattable != null)
{
if ((str == null) && (builder != null))
{
str = builder.ToString();
}
str2 = formattable.ToString(str, provider);
}
else if (arg != null)
{
str2 = arg.ToString();
}
}
if (str2 == null)
{
str2 = string.Empty;
}
int repeatCount = num4 - str2.Length;
if (!flag && (repeatCount > 0))
{
this.Append(' ', repeatCount);
}
this.Append(str2);
if (flag && (repeatCount > 0))
{
this.Append(' ', repeatCount);
}
goto Label_0096;
}
我建议大家不管是在工作中还是学习中,尽量用StringBuilder去处理字符串拼接方面的问 题,因为不管是从性能 方面,还是从用法方面,用StringBuilder绝对是一个正确的选择。 看到里面的方法了吧,我进去后又是一句我靠,忍不住来了一句所噶斯捏! 里面的循环和判 断 大致 就是一些基础 的字符串判断和叠加操作,相信你们只要用心看一定能看懂的,这里就不多 说了。 基本的对 string.Format就讲完了 ,如果大家还有不懂的可以提出来,感谢大家的 观看,谢谢!!!