c#编译器是如何处理分割的?

本文关键字:处理 分割 编译器 何处理 | 更新日期: 2023-09-27 18:06:22

我有一个List<string>,我正在迭代并拆分每个项目,然后将其添加到StringBuilder

foreach(string part in List)
{
   StringBuilder.Append(part.Split(':')[1] + " ");
}

我的问题是通过这个分割创建了多少个字符串?所有的分割都会产生两种产品。所以…我在想,它将创建一个string[2],然后是一个空字符串。但是,它是否创建string[1] + " "的连接,然后将其添加到StringBuilder,或者这是优化的?

c#编译器是如何处理分割的?

代码实际上相当于:

foreach(string part in myList)
{
   sb.Append(string.Concat(part.Split(':')[1], " "));
}

所以,是的,一个额外的string,表示分割的第二部分和空字符串的连接将被创建。

包括原始的string,您还拥有通过调用Split()创建的两个,以及对文字字符串" "的引用,该字符串将从程序集元数据加载。

您可以通过将拆分结果和空字符串依次Append来节省对Concat()的调用:

sb.Append(part.Split(':')[1]).Append(" ");
请注意,如果您只使用字符串字面值,那么编译器将为您进行一次优化:
sb.Append("This is " + "one string");

实际上被编译为

sb.Append("This is one string");

每项附加3个字符串

  • part[0];
  • part[1];
  • part[1] + " "

最小的分配可能是完全避免所有的临时分配,但通常的微优化注意事项适用。

var start = part.IndexOf(':') + 1;
stringbuilder.Append(part, start, part.Length-start).Append(' ');

您有原始字符串'split' - 1字符串

你有'split'分成两个- 2字符串

你有两个部分分割连接- 1字符串

字符串生成器不创建新字符串。

当前代码使用4个字符串,包括原来的。

如果你想保存一个字符串,执行:

StringBuilder.Append(part.Split(':')[1]);
StringBuilder.Append(" ");

代码:

foreach(string part in List)
{
   StringBuilder.Append(part.Split(':')[1] + " ");
}

等价于:

foreach(string part in List)
{
   string tmp = string.Concat(part.Split(':')[1], " ");
   StringBuilder.Append(tmp);
}

是的,它不必要地创建了一个字符串。这样会更好,至少在生成的字符串数量方面:

foreach(string part in List)
{
   StringBuilder.Append(part.Split(':')[1])
                .Append(" ");
}

因此,对于列表中的每个值(n,在您的代码中称为part),您正在分配:

  1. x(我假设2)字符串的分割。
  2. n字符串用于连接。
  3. StringBuilder的大致n + 1字符串;

最后是nx + n + n + 1,假设分割总是产生两个值4n + 1 .

改善这种情况的一种方法是:

foreach(string part in List) 
{
    var val = part.Split(':')[1];
    StringBuilder.EnsureCapacity(StringBuilder.Length + val.Length + 1);
    StringBuilder.Append(val);
    StringBuilder.Append(' ');
}

这使它成为3n + 1。这是一个粗略的估计,因为StringBuilder在耗尽空间时分配字符串-但如果您使用EnsureCapacity,则可以防止出错

可能唯一确定这是如何编译的方法是构建它并使用Refactor再次反编译,以查看它是如何内部处理的。无论如何,要记住,它可能不会对整个应用程序的性能产生影响。