views:

812

answers:

3

Given a composite format string provided by the user (for use with String.Format) and a set of types representing the arguments that would be used to format the composite format string, how can you check that the user-provided value is valid?

It should be pretty easy to create a regular expression to check that the general syntax of the argument placeholders match "{index[,alignment][:formatString]}" per the documentation. And not too much more difficult to verify that the indexes of the placeholders in the composite format string are less than the actual number of typed arguments (i.e. they don't reference an argument that won't be given). However, given the types for the arguments that will be passed in are known, it should also be possible to validate the ":formatString" is appropriate for those types.

For example, you want to validate the user doesn't specify "{0:dddd MMMM}" as a format string when the first argument type (0 index) is a number (String.Format("{0:dddd MMMM}", 1234) yields "dddd MMMM"). The quantity of ":formatString" options by type is too large to want to manually check everything. Is there any other way? Or do you just have to live with the user potentially specifying a bad format string?

Assume there are no custom IFormatProvider, ICustomFormatter or IFormattable implementations in play here. Just basic types already in the .NET Framework. Bonus points for addressing the custom stuff.

+3  A: 

There is no inbuilt way of doing this, AFAIK.

You could code every common case manually, but I don't recommend it.

(edit) One pragmatic option might be try/catch - test the format as early as possible when the user enters it....

Marc Gravell
That's what I'm looking to avoid.
iammichael
I don't even really want to do the regex for the placeholders!
iammichael
+2  A: 

Sorry, but the way to do it is:

try { string.Format(godKnowsWhat, aBunchOfArguments); }
catch(FormatException) { // use exception for control flow lol }

Yep, kinda bad.

mquander
I have types, not instances of the types, at the time the format needs to be validated so there's no "aBunchOfArguments" to provide.
iammichael
Re "instances of types"... Activator.CreateInstance ;-p
Marc Gravell
Yeah, you'll have to create instances with reflection if you want to use this method.
mquander
Activator.CreateInstance(typeof(string)) fails (missing a no-arg constructor), so creating instances is more than just reflection. Further, FormatException appears to only thrown when the indexes are bad and doesn't actually validate the ":formatString" is appropriate for the type.
iammichael
not that I'd be doing Activator.CreateInstance(typeof(string)) -- it'd be more like: foreach(Type t in types) { Activator.CreateInstance(t) } (with some other stuff). The creation will minimally have to special case string (using String.Empty). Other types may also be problemmatic (haven't tried).
iammichael
+1  A: 

If bad format string specified by user could cause exception, then maybe you can just try it out? Yes, it's naive and trivial idea.

XOR