天天看點

詳解C#string.Format性能

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