Конкатенация строк использует StringBuilder внутренне?

Три из моих коллег просто сказали мне, что нет никакой причины использовать StringBuilder вместо конкатенации с помощью + оператор. Другими словами, это прекрасно, чтобы сделать с набором строк: myString1 + myString2 + myString3 + myString4 + mySt...

Объяснение, которое они использовали, было то, что начиная с.NET 2, компилятор C# создаст тот же IL, если Вы будете использовать + оператор, как будто Вы использовали StringBuilder.

Это - новости мне. Они корректны?

12
задан dtb 20 May 2010 в 19:13
поделиться

8 ответов

Нет, они неверны. Объединение строк создает новую строку , тогда как StringBuilder использует буфер переменного размера для построения строки, создавая только объект string , когда ToString () ]называется.

Есть много дискуссий о методах конкатенации строк в Интернете, если вы хотите продолжить чтение по этой теме. Большинство из них сосредоточены на эффективности различных методов при использовании в циклах. В этом сценарии StringBuilder быстрее конкатенации строк с использованием строковых операторов для конкатенации 10 или более строк , что должно указывать на то, что он должен использовать другой метод, чем конкатенация.

Тем не менее, если вы объединяете постоянные строковые значения, строковые операторы будут лучше, потому что компилятор будет учитывать их, а если вы выполняете конкатенацию без цикла, использование операторов будет лучше, поскольку они должны привести к однократный вызов string.Concat .

25
ответ дан 2 December 2019 в 03:07
поделиться

Нет, они неверны, это не приведет к тому же IL:

static string StringBuilder()
{
    var s1 = "s1";
    var s2 = "s2";
    var s3 = "s3";
    var s4 = "s4";
    var sb = new StringBuilder();
    sb.Append(s1).Append(s2).Append(s3).Append(s4);
    return sb.ToString();
}

static string Concat()
{
    var s1 = "s1";
    var s2 = "s2";
    var s3 = "s3";
    var s4 = "s4";
    return s1 + s2 + s3 + s4;
}

IL из StringBuilder:

.method private hidebysig static string StringBuilder() cil managed
{
    .maxstack 2
    .locals init (
        [0] string s1,
        [1] string s2,
        [2] string s3,
        [3] string s4,
        [4] class [mscorlib]System.Text.StringBuilder sb)
    L_0000: ldstr "s1"
    L_0005: stloc.0 
    L_0006: ldstr "s2"
    L_000b: stloc.1 
    L_000c: ldstr "s3"
    L_0011: stloc.2 
    L_0012: ldstr "s4"
    L_0017: stloc.3 
    L_0018: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
    L_001d: stloc.s sb
    L_001f: ldloc.s sb
    L_0021: ldloc.0 
    L_0022: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
    L_0027: ldloc.1 
    L_0028: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
    L_002d: ldloc.2 
    L_002e: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
    L_0033: ldloc.3 
    L_0034: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
    L_0039: pop 
    L_003a: ldloc.s sb
    L_003c: callvirt instance string [mscorlib]System.Object::ToString()
    L_0041: ret 
}

IL из Concat:

.method private hidebysig static string Concat() cil managed
{
    .maxstack 4
    .locals init (
        [0] string s1,
        [1] string s2,
        [2] string s3,
        [3] string s4)
    L_0000: ldstr "s1"
    L_0005: stloc.0 
    L_0006: ldstr "s2"
    L_000b: stloc.1 
    L_000c: ldstr "s3"
    L_0011: stloc.2 
    L_0012: ldstr "s4"
    L_0017: stloc.3 
    L_0018: ldloc.0 
    L_0019: ldloc.1 
    L_001a: ldloc.2 
    L_001b: ldloc.3 
    L_001c: call string [mscorlib]System.String::Concat(string, string, string, string)
    L_0021: ret 
}

Также вы можете найти эту статью интересной.

16
ответ дан 2 December 2019 в 03:07
поделиться

Нет, это не так. Они определенно генерируют разные IL. Они используют разные вызовы: String.Concat в случае без StringBuilder.

String.Concat вызывает частный метод ConcatArray, который выделяет новую строку, достаточную для хранения конечного результата. Итак, это очень разные вещи, но это не значит, что конкатенация с помощью оператора + менее эффективна, чем использование StringBuilder. На самом деле, почти наверняка она более эффективна. Кроме того, в случае с конкатенацией констант, она выполняется во время компиляции.

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

5
ответ дан 2 December 2019 в 03:07
поделиться

Ответ в том, что это зависит от того, как вы объединяете. Если вы используете оператор + со статическими строками, то ваши друзья правы - нет необходимости в построителе строк. Однако, если вы используете строковые переменные или оператор + =, вы перераспределяете строки.

Чтобы действительно узнать, что здесь происходит, нужно написать код, а затем декомпилировать его.

Давайте создадим тестовый код и посмотрим на него в Reflector, используя представление IL (или вы можете использовать ILDASM, в зависимости от того, что вы предпочитаете

Итак, сначала базовый уровень - этот метод вообще не объединяет:


static void NoConcat()
{
  string test = "Hello World";
}

Теперь вот IL:


.method private hidebysig static void NoConcat() cil managed
{
    .maxstack 1
    .locals init (
        [0] string test)
    L_0000: nop 
    L_0001: ldstr "Hello World"  <----------NO reallocation!
    L_0006: stloc.0 
    L_0007: ret 
}

Хорошо, никаких сюрпризов, не так ли?

Теперь давайте посмотрим на код, который определенно перераспределяет строку, чтобы мы знали, как это выглядит:


static void Concat2()
{
  string test = "Hello";
  test += " ";
  test += "World";
}

Вот IL, обратите внимание на перераспределение ( он вызывает string.Concat, который вызывает выделение новой строки):


.method private hidebysig static void Concat2() cil managed
{
    .maxstack 2
    .locals init (
        [0] string test)
    L_0000: nop 
    L_0001: ldstr "Hello"
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ldstr " "
    L_000d: call string [mscorlib]System.String::Concat(string, string)
    L_0012: stloc.0 
    L_0013: ldloc.0 
    L_0014: ldstr "World"
    L_0019: call string [mscorlib]System.String::Concat(string, string)
    L_001e: stloc.0 
    L_001f: ret 
}

Хорошо, теперь как насчет конкатенации, которая не вызывает перераспределения - мы собираемся объединить статические строки с помощью оператора "+":


static void Concat1()
{
  string test = "Hello" + " " + "World";
}

Вот IL - посмотрите, насколько умен компилятор! Он НЕ использует concat - он идентичен первому примеру:


.method private hidebysig static void Concat1() cil managed
{
    .maxstack 1
    .locals init (
        [0] string test)
    L_0000: nop 
    L_0001: ldstr "Hello World"
    L_0006: stloc.0 
    L_0007: ret 
}

Теперь давайте немного повеселимся. Что, если мы смешаем статические строки и переменные? (Это где вам все еще может быть лучше использовать построитель строк)


static void Concat3(string text)
{
  string test = "Hello" + " " + text + " World";
}

И IL. Обратите внимание, что он был достаточно умен, чтобы объединить "Hello" и "" как константу, но он все равно должен выполнить concat для текстовая переменная:


.method private hidebysig static void Concat3(string text) cil managed
{
    .maxstack 3
    .locals init (
        [0] string test)
    L_0000: nop 
    L_0001: ldstr "Hello "
    L_0006: ldarg.0 
    L_0007: ldstr " World"
    L_000c: call string [mscorlib]System.String::Concat(string, string, string)
    L_0011: stloc.0 
    L_0012: ret 
}

4
ответ дан 2 December 2019 в 03:07
поделиться

Между конкатенацией строк и StringBuidler есть ОГРОМНАЯ разница в производительности. У нас был слишком медленный веб-сервис. Мы изменили всех строковых котов на StringBuilder.Appends, и это стало намного быстрее!

0
ответ дан 2 December 2019 в 03:07
поделиться

Я обычно следую следующим правилам:

  1. Если количество дочерних строк заранее известно, используйте конкатенацию. Это охватывает такие ситуации, как str1 + str2 + str3 + ..., независимо от того, сколько их.

  2. Если дочерние строки уже находятся в массиве, используйте string.join

  3. Если вы строите строку в цикле, используйте StringBuilder

1
ответ дан 2 December 2019 в 03:07
поделиться

Небольшая разница между String и StringBuilder:

Объединение String создаст новый строковый объект являясь результатом конкатенации. Объединение StringBuilder изменяет строковый объект.

Значит, они неверны.

0
ответ дан 2 December 2019 в 03:07
поделиться

Нет, конкатенация строк не использует внутренне StringBuilder. Однако в вашем конкретном примере использование StringBuilder не дает никаких преимуществ.

Это нормально для нескольких строк (вы создаете только одну новую строку):

myString = myString + myString2 + myString3 + myString4 + mySt...

Это не так (вы создаете и выделяете 4 строки и т. Д.):

myString = myString + myString2;
myString = myString + myString3;
myString = myString + myString4;
myString = myString + myString5;

Из всех вопросов о stackoverflow о На этот вопрос есть один из лучших ответов: String против StringBuilder

Найдите два ответа, один от Джея Базузи и один от Джеймса Каррана.

Также НАСТОЯТЕЛЬНО РЕКОМЕНДУЕТСЯ, Джефф Этвуд использует реальное тестирование для сравнения этих и других сценариев конкатенации / построения строк, здесь: http://www.codinghorror.com/blog/2009/01/the-sad-tragedy-of-micro-optimization-theater.html

0
ответ дан 2 December 2019 в 03:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: