我正在研究String.Concat :(反射器)
很奇怪:
拥有values数组,
他们创建了一个新的阵列,之后他们将他发送给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);
}
答案 0 :(得分:34)
一方面,这意味着新数组的内容可以被信任为非null ....并且不变。
如果没有复制,另一个线程可能会在调用ConcatArray
期间修改原始数组,这可能会引发异常甚至触发安全漏洞。通过复制,可以随时更改输入数组 - 每个元素只读取一次,因此不会出现不一致。 (结果可能是旧元素和新元素的混合,但最终不会导致内存损坏。)
假设ConcatArray
被信任从它传递的数组中的字符串中进行批量复制,而不检查缓冲区溢出。然后,如果您在恰当的时间更改输入数组,则可能最终在分配的内存之外写入。不良。有了这个防御性副本,系统可以确定 1 总长度确实是总长度。
1 好吧,除非使用反射来改变字符串的内容。但是如果没有相当高的权限就无法做到这一点 - 而改变数组的内容很容易。
答案 1 :(得分:16)
他们为什么要创建一个新阵列?
我可以证实乔恩的推测;我在我面前有原始的源代码。评论表明复制的原因是因为一些愚蠢的人可能改变在另一个线程上传入的数组。然后会发生什么?长度的计算可以说结果中将有一百个字节的字符串数据,但是到复制发生的时候,数组中可能有一百万字节的字符串数据。
那会很糟糕。通过复制可以轻松防止这个问题。
答案 2 :(得分:4)
他们创建了一个新数组,将null
条目规范化为String.Empty
。这不能在提供的values
数组上完成,因为它们将修改输入。
答案 3 :(得分:2)
低效
不,没关系。该数组的创建和复制相对于连接而言非常快,它只是复制引用。
看起来他们这样做是为了将输入数组中的null
字符串转换为String.Empty
(他们不能在values
上执行此操作,因为它会修改输入,即no no),并检测在实际进行连接之前会溢出的连接(这就是if(totalLength < 0)
测试的用途)。此外,他们可以使用totalLength
预先为连接字符串分配内存,这样效率更高。
答案 4 :(得分:0)
可能确保它在方法的生命周期内不会发生变化。这将导致totalLength
不再适合数组的内容。
我怀疑ConcatArray
使用了一些不安全的内存复制,并且没有再次重新检查字符串Length
。人们可以重写它以避免分配,但另外一个小的,短期的分配相当便宜。
答案 5 :(得分:0)
据我所知他们做了一些工作 - 猜你不想改变原来的那个...记住你希望你的字符串不可变同样的Concat功能当然 - 不要改变一个参数参考如果没有说明....