我的问题是: C#中的字符串连接是否安全?如果字符串连接导致意外错误,并且使用StringBuilder替换该字符串连接会导致这些错误消失,那可能表示什么?
背景:我正在开发一个小命令行C#应用程序.它接受命令行参数,执行稍微复杂的SQL查询,并将大约1300行数据输出到格式化的XML文件中.
我的初始程序总是在调试模式下正常运行.但是,在发布模式下,它将获得大约第750个SQL结果,然后因错误而死亡.错误是无法读取某一列数据,即使通过SqlDataReader对象的Read()方法刚刚返回true也是如此.
通过对代码中的所有操作使用StringBuilder来修复此问题,之前已经存在"string1 + string2".我不是在谈论SQL查询循环中的字符串连接,其中StringBuilder已经在使用中.我在谈论代码中较早的两个或三个短字符串变量之间的简单连接.
我的印象是C#足够聪明,可以通过添加几个字符串来处理内存管理.我错了吗?或者这是否表明其他一些代码问题?
考虑以下输入:
String[] input = {"a9", "aa9", "a9a9", "99a99a"};
Run Code Online (Sandbox Code Playgroud)
使用StringBuilder直接替换9之前的任何数字与字母表后面的下一个字母时,最有效的方法是什么?
处理完这些输入后,输出应为:
String[] output = {"b9", "ab9", "b9b9", "99b99a"}
Run Code Online (Sandbox Code Playgroud)
我一直在摸不着头脑,而StringBuilder.setCharAt是我能想到的最好的方法.
任何建议或意见将不胜感激.
我注意到它StringBuilder由一个数组支持,这使得它分配一个内存块。我不喜欢这种行为,因为内存高度碎片化,有时很难找到足够大的内存块,这会触发 GC...
我想知道是否有一个StringBuilder由链表备份的版本,这会更内存友好。
我正在写很多东西来登录突发,并优化数据路径.我用它构建日志文本StringBuilder.什么是最有效的初始容量,内存管理明智,所以无论JVM如何都能很好地工作?目标是避免重新分配几乎总是,应该由初始容量约80-100覆盖.但是我也希望浪费尽可能少的字节,因为StringBuilder实例可能会在缓冲区中出现并且会浪费掉浪费的字节.
我意识到这取决于JVM,但是应该有一些值,这会浪费最少的字节,无论JVM,还是"最小公分母".我目前正在使用128-16,其中128是一个很好的整数,减法用于分配开销.此外,这可能被认为是"过早优化"的情况,但由于我所追求的答案是一个"经验法则"数字,因此知道它在将来也会有用.
我不期待"我最好的猜测"答案(上面我自己的答案已经是这样),我希望有人已经研究过这个并且可以分享基于知识的答案.
我看到这个问题
回答者将长度设置为零并且还担心容量?设置容量真的很重要吗?
如果我们反汇编 .net 4.5 Library ,导航到 System.Text.StringBuilder
/// <summary>
/// Removes all characters from the current
<see cref="T:System.Text.StringBuilder"/> instance.
/// </summary>
///
/// <returns>
/// An object whose <see cref="P:System.Text.StringBuilder.Length"/>
/// is 0 (zero).
/// </returns>
[__DynamicallyInvokable]
public StringBuilder Clear()
{
this.Length = 0;
return this;
}
Run Code Online (Sandbox Code Playgroud)
当我们已经将其长度设置为零时,设置容量真的很重要吗……或者 ms 并不关心这一点?
众所周知,StringBuilder中有一个名为capacity的属性,它总是大于StringBuilder对象的长度.但是,用于什么容量?如果长度大于容量,它将被扩展.如果它做了什么,有人可以举个例子吗?
在做了一些分析之后,我们发现我们的应用程序连接字符串的当前方式会导致大量的内存流失和 CPU 时间。
我们正在构建一个List<string>长度为 50 万个元素的字符串来连接,引用数百兆字节的字符串。我们正在尝试优化我们应用程序的这一小部分,因为它似乎占用了不成比例的 CPU 和内存使用量。
我们做了很多文本处理:)
从理论上讲,我们应该能够在单个分配和 N 个副本中执行连接——我们可以知道我们的字符串中有多少个可用字符,所以它应该就像总结组件字符串的长度并分配足够的一样简单底层内存来保存结果。
假设我们从一个 pre-filled 开始List<string>,是否可以使用单个分配连接该列表中的所有字符串?
目前,我们正在使用StringBuilder该类,但它存储了所有字符的自己的中间缓冲区 - 因此我们有一个不断增长的块数组,每个块存储我们提供给它的字符的副本。远非理想。块数组的分配并不可怕,但最糟糕的是它分配了中间字符数组,这意味着 N 次分配和副本。
我们现在能做的最好的事情就是调用List<string>.ToArray()——它执行一个 500k 元素数组的副本——并将结果传递string[]给string.Concat(params string[]). string.Concat()然后执行两次分配,一次将输入数组复制到内部数组中,另一次分配目标字符串的内存。
来自 referencesource.microsoft.com:
public static String Concat(params String[] values) {
if (values == null)
throw new ArgumentNullException("values");
Contract.Ensures(Contract.Result<String>() != null);
// Spec#: Consider a postcondition saying the length of this string == the sum of each string in array
Contract.EndContractBlock();
int totalLength=0;
// …Run Code Online (Sandbox Code Playgroud) 在将字符串附加到a时StringBuilder,它的容量和长度是否可以超越它MaxCapacity?
根据MSDN MaxCapacity定义为"字符串生成器实例可以容纳的最大字符数".但是这种行为在以下两个代码片段中不一致:
代码段1:在下面的代码ArgumentOutOfRangeException中,当StringBuilder的长度超过其MaxCapacity时抛出 - 这是预期的.
String str = sb.ToString();
StringBuilder sb1 = new StringBuilder(3, 5);
sb1.Append("1"); //no error as Length 1 <= max limit 5
sb1.Append("12"); //no error as Length 3 <= max limit 5
sb1.Append("123"); //ArgumentOutOfRangeException Thrown as Length 6 > max limit 5
Run Code Online (Sandbox Code Playgroud)
代码段2:在下面的代码中,ArgumentOutOfRangeException当StringBuilder的长度超过其MaxCapacity时,抛出NO - 此行为似乎不正确.
StringBuilder sb = new StringBuilder(3, 5);
sb.Append("1"); //no error as Length 1 <= max limit 5
sb.Append("2"); //no error as Length 2 <= …Run Code Online (Sandbox Code Playgroud) 今天在VS2017 intellisense浮出水面InplaceStringBuilder时,我试图打字StringBuilder. InplaceStringBuilder对我来说是新的,所以我开始挖掘,看看我能学到什么.
我注意到的第一件事是它是一个结构而不是一个类,它的类型信息如下所示:
#region Assembly Microsoft.Extensions.Primitives, Version=1.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// C:\Users\Ron Clabo\Documents\Visual Studio 2017\Projects\wwwGiftOasisResponsive\packages\Microsoft.Extensions.Primitives.1.1.0\lib\netstandard1.0\Microsoft.Extensions.Primitives.dll
#endregion
using System.Diagnostics;
namespace Microsoft.Extensions.Primitives {
[DebuggerDisplay("Value = {_value}")]
public struct InplaceStringBuilder {
public InplaceStringBuilder(int capacity);
public int Capacity { get; set; }
public void Append(string s);
public void Append(char c);
public override string ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
所以它有很多方法比StringBuilder.然后我google了解更多信息,InplaceStringBuilder但网上关于它的内容并不多,所以它看起来很新.
此外,我已经提到的差异,InplaceStringBuilder和之间有什么不同StringBuilder; 什么时候开发人员应该使用新的InplaceStringBuilder而不是旧的StringBuilder?
我有一个tasks列表对象,我正在迭代并附加每个任务对象,StringBuilder然后是新行,如下所示.现在我将继续在同一个字符串生成器中追加任务对象,直到它达到60000字节的大小限制.一旦达到限制,我将填充此字符串作为映射中的值,键将是带增量索引的文件名.然后我将重置字符串构建器和其他东西并再次重复此过程.
因此,如果我有一个大tasks对象,那么我将拆分成多个字符串对象,其大小应始终小于60000字节.
我得到了下面的代码,但我总是看到地图中的值大小超过60000字节.我做错了什么?此外,我正在填写HashMap两个不同的地方 - 一个达到限制,另一个是如果没有达到限制.
public void populate(final List<Task> tasks) {
Map<String, String> holder = new HashMap<>();
int size = 0;
int index = 0;
StringBuilder sb = new StringBuilder();
for (Task task : tasks) {
sb.append(task).append(System.getProperty("line.separator"));
size = sb.toString().getBytes(StandardCharsets.UTF_8).length;
if (size > 60000) {
String fileName = "tasks_info_" + index + ".txt";
holder.put(fileName, sb.toString());
index++;
sb = new StringBuilder();
size = 0;
}
}
// for cases where we don't reach …Run Code Online (Sandbox Code Playgroud) stringbuilder ×10
java ×5
c# ×4
.net ×3
string ×3
.net-core ×1
algorithm ×1
asp.net-core ×1
memory ×1
utf-8 ×1