我的问题是这样的:是字符串连接在C#中安全吗?如果字符串连接会导致意想不到的错误,并通过使用StringBuilder的替换该字符串连接会导致这些错误消失,什么可能说明什么?

<强>背景我开发一个小的命令行C#应用程序。这需要命令行参数,进行稍微复杂SQL查询,并且输出约1300行的数据到一个格式化的XML文件。

我的初始程序将始终运行于调试模式细。然而,在发行模式下,它会得到约第750 SQL结果,然后用一个错误死亡。误差在该数据的某列无法读取,即使是通过SqlDataReader对象的Read()方法刚刚回到真。

此问题是固定使用的StringBuilder在代码,其中先前曾出现过“字符串1 +字符串2”的所有操作。我不是在谈论的SQL查询循环,其中的StringBuilder已经在内部使用字符串连接。我说的是两个或三个短字符串在前面的代码变量之间的简单级联。

我有印象,C#是足够聪明来处理内存管理添加了几个字符串连接在一起。我错了吗?或者这是否表明一些其他类型的代码的问题?

有帮助吗?

解决方案

除了你在做什么可能是最好的XML API,而不是字符串或StringBuilder的,我怀疑这样做了,你看到的错误是由于字符串连接。也许切换到StringBuilder的只是掩盖错误或走过去它优雅,但我怀疑使用字符串果然是原因。

其他提示

要回答你的问题: 在C#中的字符串contatenation(和.NET一般)的的“安全”,但在紧密循环做你描述很可能造成严重的内存压力,并把紧张的垃圾收集器。

我会大胆地猜测你说的错误资源某种疲惫都有关,但它是有益的,如果你能提供更多的细节 - 例如,你有没有收到异常?没有应用程序异常终止?

<强>背景 .NET字符串是不变的,所以当你做一个级联是这样的:

var stringList = new List<string> {"aaa", "bbb", "ccc", "ddd", //... };
string result = String.Empty;
foreach (var s in stringList)
{
    result = result + s;
}

这是大致等效于以下:

string result = "";
result = "aaa"
string temp1 = result + "bbb";
result = temp1;
string temp2 = temp1 + "ccc";
result = temp2;
string temp3 = temp2 + "ddd";
result = temp3;
// ...
result = tempN + x;

本实施例的目的是强调周围在一个新的临时串的分配循环的结果每个一次。

由于字符串是不可变的,运行时没有其他选择,但每次都分配一个新的字符串添加另一个字符串到你的结果结束。

虽然result字符串被不断更新,以指向最新和最好的中间结果,你是制作很多这些未命名的临时字符串,垃圾收集几乎立即成为合格的。

目前级联你将不得不存储在存储器中的以下的字符串的末尾(假设,为简单起见,该垃圾收集器尚未运行)。

string a = "aaa";
string b = "bbb";
string c = "ccc";
// ...
string temp1 = "aaabbb";
string temp2 = "aaabbbccc";
string temp3 = "aaabbbcccddd";
string temp4 = "aaabbbcccdddeee";
string temp5 = "aaabbbcccdddeeefff";
string temp6 = "aaabbbcccdddeeefffggg";
// ...

尽管所有这些隐含的临时变量几乎立即有资格进行垃圾回收,他们仍然要进行分配。当在一个紧凑的循环进行级联这是要投入大量的应变垃圾收集,如果不出意外,将会使运行你的代码非常缓慢。我已经看到了这第一手的性能的影响,并为您的连接字符串变大成为真正的戏剧性。

建议的方法是始终使用StringBuilder如果你正在做的比数字符串连接更多。 StringBuilder使用可变缓冲区,以减少在建立您的字符串需要分配的数量。

字符串连接是安全的,虽然更多的内存比如果contatenating大量在一个循环中的字符串利用一个StringBuilder密集的。在极端情况下,你可以运行内存。

这是几乎可以肯定在你的代码中的错误。

也许你contatenating一个非常大的数字串。或者,也许这是别的东西完全不同。

我会回去调试没有根源的任何成见 - 如果你仍然有问题,请尝试将其降低到到瑞普问题及邮政编码所需的最低

多久会采取串联VS版本字符串生成器的版本?这有可能是你的数据库连接被关闭。如果你正在做大量的级联,我会去瓦特/ StringBuilder的,因为它是一个比较有效的。

一个原因可能是该字符串是不可变的。Net所以当你在一个诸如级联你实际上是创建一个新的字符串。做的操作

另一个可能的原因是,字符串长度是一个int这样的最大可能长度为Int32.MaxValue或2147483647。

在任一情况下一个StringBuilder大于“字符串1 +字符串2”为这种类型的操作更好。虽然,使用内置的XML功能就更好了。

string.Concat(string[])是迄今为止来连接字符串的最快方式。在循环使用时,特别是如果你在创建每个迭代的StringBuilder它litterly杀死StringBuilder性能。 有引用的负荷,如果你在Google上搜索“C#字符串格式VS的StringBuilder”或类似的东西。 http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx为您提供有关倍ideer。这里的string.join赢得级联测试,但我相信这是因为string.Concat(string, string)代替重载的版本,以一个数组。 如果你看看由不同的方法,你就知道怎么回事引擎盖下产生的MSIL代码。

下面是我瞎猜...

在.NET(未stringbuilders)字符串进入字符串实习生池。这基本上是由CLR管理共享字符串来提高性能的区域。必须有一些在这里的限制,虽然我不知道限制是多少。我想象你正在做的是打串实习生池的顶棚的连接。所以SQL说是我对你的价值,但不能把它放在任何地方,所以你得到一个异常。

一个快速简便的测试将是 NGEN 您的程序集,看看你是否仍然得到错误。 nGen'ing后,您的应用程序将不再使用游泳池。

如果失败了,我会与Microsoft联系,试图得到一些硬的细节。我觉得我的想法听起来很有道理,但我不知道为什么它工作在调试模式。也许在调试模式字符串不拘留。我也没有专家。

当配混的字符串一起我总是使用StringBuilder。它的设计和它是更有效的,简单地使用“字符串1 +字符串2”。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top