Как компилятор C # работает с разбиением? - PullRequest
0 голосов
/ 23 августа 2011

У меня есть List<string>, который я перебираю и делю на каждый элемент, затем добавляю его к StringBuilder.

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

Итак, мой вопрос: сколько строк создается в результате этого разделения? Все сплиты собираются произвести два предмета. Итак ... Я думал, что это создаст string[2], а затем пустую строку. Но создает ли он конкатенацию string[1] + " ", а затем добавляет ее к StringBuilder или это оптимизировано?

Ответы [ 6 ]

5 голосов
/ 23 августа 2011

Код фактически эквивалентен этому:

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

Так что да, будет создан дополнительный string, представляющий конкатенацию второй части разбиения и пустой строки.

Включая исходную string, у вас также есть две, созданные путем вызова Split(), и ссылка на буквенную строку " ", которая будет загружена из метаданных сборки.

Вы можете сохранить вызов Concat(), просто Append, последовательно получив результат разделения и пустую строку:

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

Обратите внимание, что если вы используете только строковые литералы, то компилятор сделает для вас одну оптимизацию:

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

фактически компилируется в

sb.Append("This is one string");
4 голосов
/ 23 августа 2011

3 дополнительных строки для каждого элемента

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

Наименьшее возможное распределение будет заключаться в том, чтобы полностью исключить все временные распределения, но применяются обычные предупреждения микрооптимизации.

var start = part.IndexOf(':') + 1;
stringbuilder.Append(part, start, part.Length-start).Append(' ');
3 голосов
/ 23 августа 2011

У вас есть исходная строка 'split' - 1 строка

Вы разбили 'split' на две - 2 строки

У вас есть две части объединенного разделения - 1 строка

Строитель строк не создает новую строку.

В текущем коде используются 4 строки, включая оригинал.

Если вы хотите сохранить одну строку, выполните:

StringBuilder.Append(part.Split(':')[1]);
StringBuilder.Append(" ");
2 голосов
/ 23 августа 2011

Таким образом, для каждого значения в списке (n, известного как part в вашем коде) вы выделяете:

  1. x (я предполагаю 2) строки для разбиения.
  2. n строки для объединения.
  3. Примерно n + 1 строка для StringBuilder;хотя, вероятно, намного меньше.

Таким образом, у вас есть 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, вы не допустите, чтобы неправильно понял .

2 голосов
/ 23 августа 2011

Этот код:

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(" ");
}
1 голос
/ 23 августа 2011

Вероятно, единственный способ убедиться в том, как это скомпилировано, - это собрать его и снова декомпилировать с помощью Refactor, чтобы увидеть, как он обрабатывается внутри.В любом случае имейте в виду, что, вероятно, это не влияет на производительность всего приложения.

...