Do not concatenate strings inside loops

TypeName

DoNotConcatenateStringsInsideLoops

CheckId

CA1818

Category

Microsoft.Performance

Breaking Change

NonBreaking

Cause

A method iteratively builds a string inside an iteration statement, such as a for or while loop, using the System.String.Concat method or using the addition (+ or &) or addition assignment (+=) operators.

Rule Description

A System.String object is immutable. When two strings are concatenated, a new String object is created. Iterative string concatenation creates multiple strings that are un-referenced and must be garbage collected. For better performance, use the System.Text.StringBuilder class.

StringBuilder maintains a mutable character buffer, which allows string concatenation and other changes to occur without the overhead of object creation and garbage collection. The initial capacity of the StringBuilder is an important performance consideration. When the capacity is no longer sufficient to hold the string, the original buffer is discarded and another buffer is created with twice the capacity of the original.

How to Fix Violations

To fix a violation of this rule, use an instance of the StringBuilder class to build the string inside the iteration statement. After the string is built, use the System.Text.StringBuilder.ToString method to access the string.

When to Exclude Warnings

Exclude a warning from this rule if the temporary strings are used inside the iteration statement. In this case, StringBuilder does not offer a performance gain because its ToString method also creates a new String object on each iteration.

Example

The following example shows four violations of this rule, one of which should be excluded, and a method, Loop5, which satisfies the rule using a StringBuilder.

Imports System
Imports System.Globalization
Imports System.Text

Namespace PerformanceLibrary

   Class MakeString
   
      Shared currentCulture As CultureInfo = CultureInfo.CurrentCulture

      Shared Sub Main()
      
         ' Loops 1 through 4 violate this rule.
         Loop1()
         Loop2()
         Loop3()
         Loop4()
         Loop5()

      End Sub

      Shared Sub Loop1()
      
         Dim digits As String = String.Empty
         For I As Integer = 0 To 9
            digits = String.Concat(digits, I.ToString(currentCulture))
         Next I
         Console.WriteLine(digits)

      End Sub

      ' This method violates the rule but 
      ' the violation should be excluded.
      Shared Sub Loop2()
      
         Dim digits As String = String.Empty
         For I As Integer = 0 To 9
            digits = String.Concat(digits, I.ToString(currentCulture))
            Console.WriteLine(digits)
         Next I

      End Sub

      Shared Sub Loop3()
      
         Dim digits As String = String.Empty
         For I As Integer = 0 To 9
            digits = digits & I.ToString(currentCulture)
         Next I
         Console.WriteLine(digits)

      End Sub

      Shared Sub Loop4()
      
         Dim digits As String = String.Empty
         For I As Integer = 0 To 9
            digits += i.ToString(currentCulture)
         Next I
         Console.WriteLine(digits)

      End Sub

      ' This method does not cause a violation of the rule.
      Shared Sub Loop5()
      
         Dim digits As New StringBuilder()
         For I As Integer = 0 To 9
            digits.Append(I.ToString(currentCulture))
         Next I
         Console.WriteLine(digits)

      End Sub

   End Class

End Namespace
using System;
using System.Globalization;
using System.Text;

namespace PerformanceLibrary
{
   class MakeString
   {
      static CultureInfo currentCulture = CultureInfo.CurrentCulture;

      static void Main()
      {
         // Loops 1 through 4 violate this rule.
         Loop1();
         Loop2();
         Loop3();
         Loop4();
         Loop5();
      }

      static void Loop1()
      {
         string digits = string.Empty;
         for(int i = 0; i < 10; i++)
         {
            digits = String.Concat(digits, i.ToString(currentCulture));
         }
         Console.WriteLine(digits);
      }
      
      // This method violates the rule but 
      // the violation should be excluded.
      static void Loop2()
      {
         string digits = string.Empty;
         for(int i = 0; i < 10; i++)
         {
            digits = String.Concat(digits, i.ToString(currentCulture));
            Console.WriteLine(digits);
         }
      }

      static void Loop3()
      {
         string digits = string.Empty;
         for(int i = 0; i < 10; i++)
         {
            digits = digits + i.ToString(currentCulture);
         }
         Console.WriteLine(digits);
      }

      static void Loop4()
      {
         string digits = string.Empty;
         for(int i = 0; i < 10; i++)
         {
            digits += i.ToString(currentCulture);
         }
         Console.WriteLine(digits);
      }

      // This method does not cause a violation of the rule.
      static void Loop5()
      {
         StringBuilder digits = new StringBuilder();
         for(int i = 0; i < 10; i++)
         {
            digits.Append(i.ToString(currentCulture));
         }
         Console.WriteLine(digits.ToString());
      }
   }
}

Avoid unnecessary string creation

Do not call properties that clone values in loops

Test for empty strings using string length

See Also

Reference

+ Operator (C# Reference)
Concatenation Operators (Visual Basic)

Concepts

Using the StringBuilder Class