String.Format gottach


"urn:schemas-microsoft-com:office:office" /> 


I saw this recently over an
internal email list and I thought I’d share it… style="mso-spacerun: yes"> 


A developer asks:


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial; mso-ansi-language: EN-GB">I’ve found
a bug in the way String.Format handles close curly literals.  It’s provoked
by having a format specifier on a string.  The attached code demonstrates
this on .NET Framework 1.1.  The core of it goes as follows:


style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-GB">//
BUG: “}}” to get a literal “}” doesn’t work
// when “:d” (or other) format
specifier is present:

style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-GB">string lang=EN-GB
style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-ansi-language: EN-GB">
wrong = String.Format(“{{{0:d}}}”, 42);


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial; mso-ansi-language: EN-GB">Here I’d
expect the produced string to be “{42}”, but instead I get “{d}”.  I first
ran into this bug using the :x (hex) format specifier, so I expect others are
also implicated.


Kit George, the PM for this
feature responds:


 


This actually isn’t a bug.


Consider this example:


 


style="FONT-FAMILY: 'Courier New'">string right1=String.Format(“{0:d!}”,
42);


 


We know that’s the wrong format
specifier in the middle there (d!), but if we Console.WriteLine the result, we
get:


 


style="FONT-FAMILY: 'Courier New'">d!


style="FONT-FAMILY: 'Courier New'"> 


Going a step further:


 


style="FONT-FAMILY: 'Courier New'">string right3=String.Format(“{{{0:d!}}}”,
42); style="mso-spacerun: yes">           


 


produces


style="FONT-FAMILY: 'Courier New'">{d!}


 


So the first thing we know is, if
you put in  a string for the
specifier that is longer than one character, string.format simply prints that
literal out.


 


The reason you’re item comes out
the way it does, is because we resolve the escaped curly brackets in the order
we’re given them. Therefore:


 


style="FONT-FAMILY: 'Courier New'">{{ style="mso-spacerun: yes">     is escaped


style="FONT-FAMILY: 'Courier New'">{0:d looks like formatting


style="FONT-FAMILY: 'Courier New'">}} style="mso-spacerun: yes">       is
escaped


style="FONT-FAMILY: 'Courier New'">} style="mso-spacerun: yes">        ends
the formatting section


 


Therefore, the formatting routine
thinks that what’s in the formatting section is in fact:


 


style="FONT-FAMILY: 'Courier New'">0:d}


 


It therefore simply prints out
d} as a literal, just like it
prints out d!, if that’s what we
had given it.


 


However, I have made sure the
docs for this area get cleaned up to make this more clear.

Comments (6)

  1. RichB says:

    Despite it being the correct behavior, it’s not very intuitive is it? – surely a goal of .Net is to have an intuitive API and get away from Candy Manchine Interfaces.

    The Format function could be made more intuitive by simply not doing the token lookahead at line 1065 (ROTOR builds) inside of StringBuilder::AppendFormat(). From the looks of things, all this would involve is the removal of 3 lines of code!

  2. Juan Felipe says:

    Maybe it isn’t a bug, but it really is unexpected. I think the "correct" behavior isn’t always (at least in this case) the "desired" behavior…. and as RichB said "a goal of .Net is to have an intuitive API". So in this case, the "correct" behavior is indeed a BUG. (at least for me)

  3. ouch – talk about non-intuitive implementations…

    Are there any format-strings that would actually need an embedded "}"? if not, I see no reason not to simply take the first } after a format specifier as the end of that specifier… At least that way it would be possible to put a "}" after a format-specifier (which is bound to be a much more common case as someone wanting one inside the specifier)

  4. Michael Entin says:

    I agree with previos three posters – maybe it is not an implementation bug, but it surely looks like design bug to me. Since format specifiers don’t use "}", it should not be treated as part of such.

    By the way, is there a reasonable workaround for those who want to print "{42}"?

  5. Kit George [MSFT] says:

    Guys, this is great feedback, thanks. You can workaround this in the meantime pretty easily:
    Double d = 42;
    Console.WriteLine("{0}{1}{2}", "{". d, "}");

    However, we will look at wheter we need to change this behavior to make it more intuitive