StringBuilder.ToString() vs Reflection

I had an intriguing conversation with a friend on Friday about the performance of using the StringBuilder.ToString() method to return the value of the String contained in the StringBuilder object.  Following this conversation, I decided to take a deeper look at how StringBuilder works.  Here is the StringBuilder.ToString() method code from Reflector:

 public override string ToString()
{
  string stringValue = this.m_StringValue;
  if (this.m_currentThread != Thread.InternalGetCurrentThread())
  {
    return string.InternalCopy(stringValue);
  }
  if ((2 * stringValue.Length) < stringValue.ArrayLength)
  {
    return string.InternalCopy(stringValue);
  }
  stringValue.ClearPostNullChar();
  this.m_currentThread = IntPtr.Zero;
  return stringValue;
}

As you can see, there is a bit of overhead to this method.  It performs some thread-safe checks and some bounding checks.  This overhead is typically minimal, but it can be quite expensive as the size of the String grows.  I decided to use a code timer (taken from Vance Morrison) to test how much the overhead grows as the String size is incremented.  As expected, the time taken to execute the method grows at about the same rate as the size of the String.  If the size of the String is doubled, then the time taken to execute the method is roughly doubled.  (BTW, I am performing this test on a Pentium 4 HT 3.60GHz, 4GB RAM, and 64-bit OS).

This does not seem to be a problem for typical small strings (<1K).   However, if you get over 1-2K, the time taken to execute the method becomes very costly.  So what if we could get the String value in the StringBuilder another way without all of the ToString() method overhead.  Well, we can do that using reflection:

 public static string GetStringValue(StringBuilder sb)
{
  lock (sb)
  {
    return (string)sb.GetType().GetField("m_StringValue", 
      BindingFlags.Instance | BindingFlags.NonPublic).GetValue(sb);
  }
}

"m_StringValue" is the internal field in which StringBuilder stores the value of the string.  As we all know, reflection also comes with some costly overhead.  After doing a comparison, if the String in the StringBuilder is 20 characters in length, ToString() is roughly 175 times faster than using reflection.  Below are some other comparisons that I did:

Length Results (approximates)
20 ToString() 175 times faster than Reflection
100 ToString() 100 times faster than Reflection
1000 ToString() 10 times faster than Reflection
10000 ToString() the same as Reflection
20000 ToString() 1.6 times slower than Reflection
50000 ToString() 8.5 times slower than Reflection

 As you can see, as the String gets larger the time taken to execute also increases.  However, the time taken to get the value using reflection stays constant regardless of the length of the String. 

Now, when are you ever going to use StringBuilder to manipulate a 50K string?  Not a very common task.   But if you ever do need to do that, you might be able to save a little execution time by utilizing reflection to get the value.