大家使用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就講完了 ,如果大家還有不懂的可以提出來,感謝大家的 觀看,謝謝!!!