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


当前回答

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

注:在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的代码。否则,只需使用+运算符。

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 });

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

尝试这两段代码,您将找到解决方案。

 static void Main(string[] args)
    {
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < 10000000; i++)
        {
            s.Append( i.ToString());
        }
        Console.Write("End");
        Console.Read();
    }

Vs

static void Main(string[] args)
    {
        string s = "";
        for (int i = 0; i < 10000000; i++)
        {
            s += i.ToString();
        }
        Console.Write("End");
        Console.Read();
    }

你会发现第一个代码将很快结束,内存将在一个很好的数量。

第二个代码可能内存没问题,但会花更长的时间…更长的时间。 所以如果你有一个用户很多的应用程序,你需要速度,使用第一个。如果你有一款短期单用户应用,也许你可以同时使用两款应用,或者对开发者来说第二款应用更“自然”。

欢呼。

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

注:在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)