连接字符串最有效的方法是什么?


当前回答

我已经测试了本页中的所有方法,最后我开发出了最快且内存成本更低的解决方案。

注:在Framework 4.8中测试

 [MemoryDiagnoser]
public class StringConcatSimple
{
    private string
        title = "Mr.", firstName = "David", middleName = "Patrick", lastName = "Callan";

    [Benchmark]
    public string FastConcat()
    {
        return FastConcat(
            title, " ", 
            firstName, " ",
            middleName, " ", 
            lastName);
    }

    [Benchmark]
    public string StringBuilder()
    {
        var stringBuilder =
            new StringBuilder();

        return stringBuilder
            .Append(title).Append(' ')
            .Append(firstName).Append(' ')
            .Append(middleName).Append(' ')
            .Append(lastName).ToString();
    }

    [Benchmark]
    public string StringBuilderExact24()
    {
        var stringBuilder =
            new StringBuilder(24);

        return stringBuilder
            .Append(title).Append(' ')
            .Append(firstName).Append(' ')
            .Append(middleName).Append(' ')
            .Append(lastName).ToString();
    }

    [Benchmark]
    public string StringBuilderEstimate100()
    {
        var stringBuilder =
            new StringBuilder(100);

        return stringBuilder
            .Append(title).Append(' ')
            .Append(firstName).Append(' ')
            .Append(middleName).Append(' ')
            .Append(lastName).ToString();
    }

    [Benchmark]
    public string StringPlus()
    {
        return title + ' ' + firstName + ' ' +
            middleName + ' ' + lastName;
    }

    [Benchmark]
    public string StringFormat()
    {
        return string.Format("{0} {1} {2} {3}",
            title, firstName, middleName, lastName);
    }

    [Benchmark]
    public string StringInterpolation()
    {
        return
        $"{title} {firstName} {middleName} {lastName}";
    }

    [Benchmark]
    public string StringJoin()
    {
        return string.Join(" ", title, firstName,
            middleName, lastName);
    }

    [Benchmark]
    public string StringConcat()
    {
        return string.
            Concat(new String[]
            { title, " ", firstName, " ",
                middleName, " ", lastName });
    }
}

是的,它使用不安全

public static unsafe string FastConcat(string str1, string str2, string str3, string str4, string str5, string str6, string str7)
    {
        var capacity = 0;

        var str1Length = 0;
        var str2Length = 0;
        var str3Length = 0;
        var str4Length = 0;
        var str5Length = 0;
        var str6Length = 0;
        var str7Length = 0;

        if (str1 != null)
        {
            str1Length = str1.Length;
            capacity = str1Length;
        }

        if (str2 != null)
        {
            str2Length = str2.Length;
            capacity += str2Length;
        }

        if (str3 != null)
        {
            str3Length = str3.Length;
            capacity += str3Length;
        }

        if (str4 != null)
        {
            str4Length = str4.Length;
            capacity += str4Length;
        }

        if (str5 != null)
        {
            str5Length = str5.Length;
            capacity += str5Length;
        }

        if (str6 != null)
        {
            str6Length = str6.Length;
            capacity += str6Length;
        }

        if (str7 != null)
        {
            str7Length = str7.Length;
            capacity += str7Length;
        }


        string result = new string(' ', capacity);

        fixed (char* dest = result)
        {
            var x = dest;

            if (str1Length > 0)
            {
                fixed (char* src = str1)
                {
                    Unsafe.CopyBlock(x, src, (uint)str1Length * 2); 
                    x += str1Length;
                }
            }

            if (str2Length > 0)
            {
                fixed (char* src = str2)
                {
                    Unsafe.CopyBlock(x, src, (uint)str2Length * 2);
                    x += str2Length;
                }
            }

            if (str3Length > 0)
            {
                fixed (char* src = str3)
                {
                    Unsafe.CopyBlock(x, src, (uint)str3Length * 2);
                    x += str3Length;
                }
            }

            if (str4Length > 0)
            {
                fixed (char* src = str4)
                {
                    Unsafe.CopyBlock(x, src, (uint)str4Length * 2);
                    x += str4Length;
                }
            }

            if (str5Length > 0)
            {
                fixed (char* src = str5)
                {
                    Unsafe.CopyBlock(x, src, (uint)str5Length * 2);
                    x += str5Length;
                }
            }

            if (str6Length > 0)
            {
                fixed (char* src = str6)
                {
                    Unsafe.CopyBlock(x, src, (uint)str6Length * 2);
                    x += str6Length;
                }
            }

            if (str7Length > 0)
            {
                fixed (char* src = str7)
                {
                    Unsafe.CopyBlock(x, src, (uint)str7Length * 2);
                }
            }
        }

        return result;
    }

您可以编辑该方法并使其适应您的情况。例如,你可以让它像这样

FastConcat(string str1, string str2, string str3 = null, string str4 = null, string str5 = null, string str6 = null, string str7 = null)

其他回答

对于只有两个字符串,您肯定不希望使用StringBuilder。如果超过某个阈值,StringBuilder开销将小于分配多个字符串的开销。

所以,对于超过2-3个字符串,使用DannySmurf的代码。否则,只需使用+运算符。

. net性能专家Rico Mariani有一篇关于这个主题的文章。这并不像人们想象的那么简单。基本的建议是:

如果你的图案是这样的: X = f1(…)+ f2(…)+ f3(…)+ f4(…) 这是一个concat,它是活泼的,StringBuilder可能不会有帮助。 如果你的图案是这样的: 如果(…)x += f1(…) 如果(…)x += f2(…) 如果(…)x += f3(…) 如果(…)x += f4(…) 那么你可能需要StringBuilder。

另一篇支持这一说法的文章来自Eric Lippert,他详细描述了在一行+连接上执行的优化。

另一个解决方案:

在循环中,使用List而不是string。

List<string> lst= new List<string>();

for(int i=0; i<100000; i++){
    ...........
    lst.Add(...);
}
return String.Join("", lst.ToArray());;

它非常非常快。

系统。字符串是不可变的。当我们修改一个字符串变量的值时,一个新的内存被分配给新的值,之前的内存分配被释放。系统。StringBuilder被设计为具有可变字符串的概念,其中可以执行各种操作,而无需为修改后的字符串分配单独的内存位置。

StringBuilder.Append()方法比使用+操作符要好得多。但我发现,当执行1000个或更少的连接时,String.Join()甚至比StringBuilder更有效。

StringBuilder sb = new StringBuilder();
sb.Append(someString);

String的唯一问题。Join是指必须使用公共分隔符连接字符串。

编辑:正如@ryanversaw指出的,可以将分隔符设置为string.Empty。

string key = String.Join("_", new String[] 
{ "Customers_Contacts", customerID, database, SessionID });