我了解StringBuilder的好处。
但是,如果我想连接2个字符串,那么我认为不使用StringBuilder这样做会更好(更快)。它是否正确?
在什么时候(字符串数)使用StringBuilder会更好?
我了解StringBuilder的好处。
但是,如果我想连接2个字符串,那么我认为不使用StringBuilder这样做会更好(更快)。它是否正确?
在什么时候(字符串数)使用StringBuilder会更好?
Answers:
但是,如果我想隐含2个字符串,那么我认为不使用StringBuilder这样做会更好(更快)。它是否正确?
确实是正确的,您可以找到为什么对以下内容进行了很好的解释:
http://www.yoda.arachsys.com/csharp/stringbuilder.html
总结:如果您可以一口气将字符串融合起来,例如
var result = a + " " + b + " " + c + ..
如果没有StringBuilder,最好只复制一次(结果字符串的长度是预先计算的)。
对于像这样的结构
var result = a;
result += " ";
result += b;
result += " ";
result += c;
..
每次都会创建新对象,因此应该考虑使用StringBuilder。
最后,文章总结了以下经验法则:
经验法则
那么,什么时候应该使用StringBuilder,什么时候应该使用字符串连接运算符?
在非平凡的循环中进行连接时,绝对可以使用StringBuilder-尤其是如果您不确定(在编译时)要在循环中进行多少次迭代时,尤其如此。例如,一次读取文件中的一个字符,并在使用+ =运算符时建立字符串可能会导致性能下降。
当您可以(可读地)指定需要在一条语句中连接的所有内容时,一定要使用连接运算符。(如果有一系列要连接的东西,请考虑显式调用String.Concat-或如果需要分隔符,则调用String.Join。)
不要害怕将文字分解为多个连接的位-结果将是相同的。您可以通过将长文字分成几行来提高可读性,例如,不影响性能。
如果您需要级联的中间结果而不是提供级联的下一个迭代,StringBuilder不会为您提供帮助。例如,如果您从名字和姓氏中建立起一个全名,然后在结尾添加第三条信息(可能是昵称),则只有在不使用StringBuilder的情况下才能受益需要(名字+姓氏)字符串用于其他目的(如在创建Person对象的示例中所做的那样)。
如果您只需要执行几个串联操作,而您真的想在单独的语句中进行操作,那么走哪条路并不重要。哪种方法更有效将取决于所涉及的字符串大小的串联数量以及串联的顺序。如果您真的认为那段代码是性能瓶颈,则可以两种方式对其进行配置或基准测试。
并非如此...如果连接大型字符串或有许多串联(例如循环),则应使用StringBuilder 。
StringBuilder
仅当循环或串联是规范的性能问题时,才应使用。
string s = "abcd"
,至少这是最后一件事我听说...尽管有变量,但很有可能是Concat。
a + "hello" + "somethingelse"
而不必担心。如果这将成为问题,我将使用StringBuilder。但是我一开始并不担心它,而花了更少的时间来编写它。
这是一个简单的测试应用程序来证明这一点:
class Program
{
static void Main(string[] args)
{
const int testLength = 30000;
var StartTime = DateTime.Now;
//TEST 1 - String
StartTime = DateTime.Now;
String tString = "test string";
for (int i = 0; i < testLength; i++)
{
tString += i.ToString();
}
Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString());
//result: 2000 ms
//TEST 2 - StringBuilder
StartTime = DateTime.Now;
StringBuilder tSB = new StringBuilder("test string");
for (int i = 0; i < testLength; i++)
{
tSB.Append(i.ToString());
}
Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString());
//result: 4 ms
Console.ReadLine();
}
}
结果:
30'000次迭代
1000次迭代
500次迭代
但是,如果我想连接2个字符串,那么我认为没有StringBuilder这样做会更好,更快。它是否正确?
是。但更重要的是,在这种情况下使用香草更具可读性String
。另一方面,在循环中使用它是有意义的,并且也可以像串联一样可读。
我会警惕以串联的特定数量作为阈值的经验法则。在循环中(仅循环)使用它可能同样有用,更容易记住并且更有意义。
由于很难找到一个既不受观点影响也不引起骄傲之争的解释,所以我想在LINQpad上编写一些代码来进行自我测试。
我发现使用小型字符串而不是使用i.ToString()会更改响应时间(在小循环中可见)。
该测试使用不同的迭代序列,以将时间测量值保持在合理的可比范围内。
我将在最后复制代码,以便您可以自己尝试(results.Charts ... Dump()在LINQPad之外无法使用)。
输出(X轴:测试的迭代次数,Y轴:以秒为单位的时间):
代码(使用LINQPad 5编写):
void Main()
{
Test(2, 3, 4, 5, 6, 7, 8, 9, 10);
Test(10, 20, 30, 40, 50, 60, 70, 80);
Test(100, 200, 300, 400, 500);
}
void Test(params int[] iterationsCounts)
{
$"Iterations sequence: {string.Join(", ", iterationsCounts)}".Dump();
int testStringLength = 10;
RandomStringGenerator.Setup(testStringLength);
var sw = new System.Diagnostics.Stopwatch();
var results = new Dictionary<int, TimeSpan[]>();
// This call before starting to measure time removes initial overhead from first measurement
RandomStringGenerator.GetRandomString();
foreach (var iterationsCount in iterationsCounts)
{
TimeSpan elapsedForString, elapsedForSb;
// string
sw.Restart();
var str = string.Empty;
for (int i = 0; i < iterationsCount; i++)
{
str += RandomStringGenerator.GetRandomString();
}
sw.Stop();
elapsedForString = sw.Elapsed;
// string builder
sw.Restart();
var sb = new StringBuilder(string.Empty);
for (int i = 0; i < iterationsCount; i++)
{
sb.Append(RandomStringGenerator.GetRandomString());
}
sw.Stop();
elapsedForSb = sw.Elapsed;
results.Add(iterationsCount, new TimeSpan[] { elapsedForString, elapsedForSb });
}
// Results
results.Chart(r => r.Key)
.AddYSeries(r => r.Value[0].Ticks, LINQPad.Util.SeriesType.Line, "String")
.AddYSeries(r => r.Value[1].Ticks, LINQPad.Util.SeriesType.Line, "String Builder")
.DumpInline();
}
static class RandomStringGenerator
{
static Random r;
static string[] strings;
public static void Setup(int testStringLength)
{
r = new Random(DateTime.Now.Millisecond);
strings = new string[10];
for (int i = 0; i < strings.Length; i++)
{
strings[i] = Guid.NewGuid().ToString().Substring(0, testStringLength);
}
}
public static string GetRandomString()
{
var indx = r.Next(0, strings.Length);
return strings[indx];
}
}
一个字符串连接不值得使用StringBuilder。根据经验,我通常使用5个串联。