String.Concat效率低下的代码?

Roy*_*mir 24 c# string concatenation .net-4.0

我在调查String.Concat :(反射器)

在此输入图像描述

很奇怪 :

有值数组,

他们创造了一个新的阵列,以后他们会把他送到ConcatArray.

题 :

为什么他们创建了一个阵列?他们values从一开始......

编辑

代码:

public static string Concat(params string[] values)
{
    if (values == null)
    {
        throw new ArgumentNullException("values");
    }
    int totalLength = 0;
    string[] strArray = new string[values.Length];
    for (int i = 0; i < values.Length; i++)
    {
        string str = values[i];
        strArray[i] = (str == null) ? Empty : str;
        totalLength += strArray[i].Length;
        if (totalLength < 0)
        {
            throw new OutOfMemoryException();
        }
    }
    return ConcatArray(strArray, totalLength);
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 34

好吧,有一点,它意味着新数组的内容可以被信任为非null ....并且不变.

如果没有复制,另一个线程可以在调用期间修改原始数组ConcatArray,这可能会引发异常甚至触发安全漏洞.通过复制,可以随时更改输入数组 - 每个元素只读取一次,因此不会出现不一致.(结果可能是旧元素和新元素的混合,但最终不会导致内存损坏.)

假设ConcatArray被信任从它传递的数组中的字符串中进行批量复制,而不检查缓冲区溢出.然后,如果您在恰当的时间更改输入数组,则可能最终在分配的内存之外写入.不良.使用这个防御性副本,系统可以确定1总长度确实是总长度.


1好吧,除非使用反射来改变字符串的内容.但是如果没有相当高的权限就无法做到这一点 - 而改变数组的内容很容易.

  • @Jason:你是对的; 我应该说,我所说的"安全"不是"线程安全" - 不管是什么 - 而是*记忆安全*.字符串代码在幕后使用不安全的代码来填充新的缓冲区,我们必须不惜一切代价避免破坏内存.如果结果是无意义的,因为有人改变了在另一个线程上使用的数组,那就是他们的问题; 至少有*是*结果和未损坏的堆. (6认同)
  • 你的猜想是正确的; 这是为了确保有人在另一个线程上修改数组时的安全性. (4认同)

Eri*_*ert 16

他们为什么要创建一个新阵列?

我可以证实乔恩的推测; 我在我面前有原始的源代码.评论表明复制的原因是因为一些愚蠢的人可能会改变在另一个线程上传入的数组.然后会发生什么?长度的计算可以说结果中将有一百个字节的字符串数据,但是到复制发生的时候,数组中可能有一百万字节的字符串数据.

那会很糟糕.通过复制可以轻松防止问题.

  • 也许这可能是一个提醒读者的好时机,因为[Microsoft Reference Source](一般情况下,不需要成为C#编译器开发人员(甚至是Microsoft员工)才能真正看到大多数框架程序集的原始源代码. http://referencesource.microsoft.com/)计划. (6认同)
  • @phoog:对; 被阻止的问题是*内存损坏*.由于竞争条件,输出字符串仍然可以与输入字符串完全无关,但内存不会被破坏. (4认同)