字符串连接在C#中不安全,需要使用StringBuilder吗?

Bry*_*ach 5 c# string stringbuilder string-concatenation

我的问题是: C#中的字符串连接是否安全?如果字符串连接导致意外错误,并且使用StringBuilder替换该字符串连接会导致这些错误消失,那可能表示什么?

背景:我正在开发一个小命令行C#应用程序.它接受命令行参数,执行稍微复杂的SQL查询,并将大约1300行数据输出到格式化的XML文件中.

我的初始程序总是在调试模式下正常运行.但是,在发布模式下,它将获得大约第750个SQL结果,然后因错误而死亡.错误是无法读取某一列数据,即使通过SqlDataReader对象的Read()方法刚刚返回true也是如此.

通过对代码中的所有操作使用StringBuilder来修复此问题,之前已经存在"string1 + string2".我不是在谈论SQL查询循环中的字符串连接,其中StringBuilder已经在使用中.我在谈论代码中较早的两个或三个短字符串变量之间的简单连接.

我的印象是C#足够聪明,可以通过添加几个字符串来处理内存管理.我错了吗?或者这是否表明其他一些代码问题?

Dan*_*nov 15

回答你的问题: C#中的字符串连接(以及一般的.NET) "安全的",但是如你所描述的那样在紧密循环中执行它可能会导致严重的内存压力并给垃圾收集器带来压力.

我猜想你所说的错误与某种资源耗尽有关,但如果你能提供更多详细信息会有所帮助 - 例如,你收到了例外吗?应用程序是否异常终止?

背景: .NET字符串是不可变的,所以当你进行这样的连接时:

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

这大致相当于以下内容:

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;
Run Code Online (Sandbox Code Playgroud)

此示例的目的是强调每次循环都会导致分配新的临时字符串.

由于字符串是不可变的,因此运行时没有其他选项,只是在每次向结果末尾添加另一个字符串时分配新字符串.

尽管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";
// ...
Run Code Online (Sandbox Code Playgroud)

虽然所有这些隐式临时变量几乎都可以立即进行垃圾收集,但仍然必须进行分配.在紧密循环中执行连接时,这将给垃圾收集器带来很大的压力,如果不出意外,将使代码运行得非常慢.我已经看到了这个第一手的性能影响,随着你的连接字符串变大,它变得非常引人注目.

建议的方法是,StringBuilder如果您进行的不仅仅是几个字符串连接,请始终使用a . StringBuilder使用可变缓冲区来减少构建字符串所需的分配数.

  • 我很确定+ b + c + d ...在单个语句中不生成中间字符串.它更像String.Concat. (4认同)

Joe*_*Joe 11

如果在循环中连接大量字符串,则串联连接比使用StringBuilder更加内存密集.在极端情况下,你可能会耗尽内存.

这几乎肯定是代码中的一个错误.

也许你正在连接大量的字符串.或者也许是完全不同的东西.

我会在没有任何先入为主的原因的情况下重新进行调试 - 如果您仍然遇到问题,请尝试将其降低到重现问题和发布代码所需的最低限度.


Joe*_*oey 7

除了你正在做的事情可能最好用XML API代替字符串或StringBuilder我怀疑你看到的错误是由字符串连接引起的.也许切换到StringBuilder只是掩盖了错误或优雅地过了它,但我怀疑使用字符串真的是原因.