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


当前回答

另一个解决方案:

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

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

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

它非常非常快。

其他回答

如果你在循环中操作,StringBuilder可能是最好的选择;它节省了定期创建新字符串的开销。在只运行一次的代码中,字符串。Concat可能没问题。

然而,Rico Mariani(。NET优化大师)做了一个测试,他在测试的最后说,在大多数情况下,他建议使用String.Format。

这取决于代码。 StringBuilder通常更高效,但如果您只是连接几个字符串并在一行中完成所有操作,那么代码优化可能会为您解决这个问题。考虑代码的外观也很重要:对于较大的集合,StringBuilder将使其更容易阅读,对于较小的集合,StringBuilder只会增加不必要的混乱。

最有效的方法是使用StringBuilder,如下所示:

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@jonezy:字符串。Concat是好的,如果你有一些小东西。但是,如果您正在连接兆字节的数据,那么您的程序可能会崩溃。

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

这是我为我的大规模NLP应用程序进化了十多年来最快的方法。我有IEnumerable<T>和其他输入类型的变化,有和没有不同类型的分隔符(Char, String),但在这里我展示了将数组中的所有字符串连接到单个字符串的简单情况,没有分隔符。这里的最新版本是在c# 7和。net 4.7上开发和单元测试的。

提高性能有两个关键;第一种方法是预先计算所需的确切总大小。当输入是如下所示的数组时,这一步是微不足道的。为了处理IEnumerable<T>,值得首先将字符串收集到一个临时数组中以计算总数(该数组需要避免每个元素多次调用ToString(),因为从技术上讲,考虑到副作用的可能性,这样做可能会改变'字符串连接'操作的预期语义)。

接下来,给定最终字符串的总分配大小,通过就地构建结果字符串可以获得最大的性能提升。要做到这一点,需要使用(可能有争议的)技术暂时暂停新String的不可变性,该String最初被分配为全0。然而,抛开这些争议不谈……

...请注意,这是本页上唯一的大容量连接解决方案,它完全避免了String构造函数额外的分配和复制。

完整的代码:

/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
    int i;
    if (rg == null || (i = rg.Length) == 0)
        return String.Empty;

    if (i == 1)
        return rg[0];

    String s, t;
    int cch = 0;
    do
        cch += rg[--i].Length;
    while (i > 0);
    if (cch == 0)
        return String.Empty;

    i = rg.Length;
    fixed (Char* _p = (s = new String(default(Char), cch)))
    {
        Char* pDst = _p + cch;
        do
            if ((t = rg[--i]).Length > 0)
                fixed (Char* pSrc = t)
                    memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
        while (pDst > _p);
    }
    return s;
}

[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);

我应该提到,这段代码与我自己使用的代码相比略有修改。在原文中,我从c#调用cpblk IL指令来执行实际的复制。为了代码的简单性和可移植性,我将其替换为P/Invoke memcpy,如您所见。为了在x64(但可能不是x86)上获得最高性能,您可能想要使用cpblk方法。