String.Format vs StringBuilder.AppendFormat

So here’s a question, what’s the difference between String.Format( string, object[]) and StringBuilder.AppendFormat( string, object[] ) ?

For those of you thate don’t know, String.Format allows you to parameterize your strings, by placing replacement tokens througout a string template.  You can later fill in those tokens with parameterized data by passing it in as an array. Here is an example:

string.Format("I own a {0} and {1} name is '{2}'", 
        "cat", "her", "Ellie" );

Of course this would output the sentence: “I own a cat and her name is ‘Ellie'”.  You can also achieve the same thing by calling StringBuilder.AppendFormat much like the following example:

StringBuilder sb = new StringBuilder();
sb.AppendFormat( "I own a {0} and {1} name is {2}", 
        "cat", "her", "Ellie" );

At first glance, you may be thinking that these are somewhat interchangable with the exception of performance. By now, we all know StringBuilder is usually faster for excessive string manipulation. What you may not know is that string.format calls the StringBuilder.AppendFormat method under the hood.  Additionally, StringBuilder will throw an exception if the number of parameters does not match the number of tokens found in the template string.  Try compiling and running a program that executes the following statement:

[STAThread]
static void Main(string[] args) {
  string x = string.Format(
    "{4} owns a {0} and {1} name is {2}.", "cat", "her", "Ellie" ); 
  Console.WriteLine( x );
  // For those of you that know WriteLine takes format strings... shhhhh
  // I'm trying to make a point here!
}

You will receive the following exception.

An unhandled exception of type 'System.FormatException' 
occurred in mscorlib.dll

Additional information: Index (zero based) must be greater 
than or equal to zero and less than the size of the argument 
list.

This exception is actually thrown by StringBuilder.AppendFormat and the String.Format method bubbles the exception up without providing the consumer with any recourse if the parameters dont’ match up.  However, if you call StringBuilder.AppendFormat yourself, you can place the code in a try catch block, and reap the benefits of a string that has been formatted as best as it can be with the parameters provided. Take the following code, for instance:

[STAThread]
static void Main(string[] args) { 
  StringBuilder sb = new StringBuilder();
  try {
    sb.AppendFormat( "{0} owns a {1} and {2} name is {3}.",
        new object[] {"Tobin", "cat", "her"} );
  }
  catch(FormatException ex) {
    Console.WriteLine("An exception occurred: {0}", ex.Message ); 
  }
  finally { 
    Console.WriteLine( sb.ToString() ); 
  } 
  Console.ReadLine();
}

Notice here that we have caught the exception, reported on it, but can still write the string builder’s text to the screen — or at least the part that was parsed.

Now here’s the questions I pose for all of you:

  1. Since you now know that you can bypass the token-count to parameter-count validation check by using StringBuilder, should you incorporate this into your applications in instances where you don’t know how many parameters you are going to have?
  2. Would you consider this to be a bug, or a reasonable feature and why?

Be Sociable, Share!

    4 Thoughts on “String.Format vs StringBuilder.AppendFormat

    1. 1.) I don’t do C# so I don’t know the API but generally it’s pretty bad form to rely on exception behavior as part of the main program logic. By definition an exception is just that an exceptional circumstance that wasn’t anticipated or that doesn’t allow the logic to continue. If you are expecting it then it isn’t really an exception. Also if it’s not documented that this will work relying on it would be really bad as it may change in the next release of the language. In addition exceptions in most languages unwind the stack looking for a handler which is an expensive operation putting that in production code would be bad.

      2.) It would depend on the if the behavior is documented or not in the API. If I found it in production code and it’s documented to always work that way in the C# API I’d call it bad form. If it’s not documented then it’s relying on undefined behavior which is a bug waiting to happen.

    2. 1) huh? How exactly do you plan on making use of this technique??
      s.AppendFormat(“Hello, World!{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}”, arr);

      Since you’d have to specify the placeholds in the format string, you’d either have to put a lot of dummy ones in (as above), or build the format string first — which makes the full exercise pretty pointless.

      2) One the whole, the fact that StringBuilder leave itself half-built when an exception is thrown would be a bug.

    3. Well, this is why I asked the question. I feel that the state of the string left after the exception is inconsistent. While I realize we aren’t talking transactions here, I do think that the state should be returned to what it was before the exception. Someone I know was using this technique to render a string regardless of whether all 4 paramters were passed. In general, I thought the whole thing was a bit buggy to me and shouldn’t have been used this way on purpose.

    4. Good article. I was asking that exact question–what’s the difference? This answered it nicely. Just throwing in my $0.02, I agree with Andy. I’m sure MS had their reasons for StringBuilder throw an exception when not all replacement parameters have specified values. However, I wouldn’t use it (i.e. catch the exception) for “optional” replacement parameters that are omitted. I can imagine that you might want to catch the exception in exceptional circumstances and possibly “recover” from it (since it’s only a string operation that failed)–but beyond recovery scenarios, I don’t see much utility in catching the exception in the general case.

      Thanks again for the article.

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    Post Navigation