views:

69

answers:

4

Given the following method: (real method has a few more parameters, but the important ones are below...)

public string DoSomething(string formatter, params string[] values)
{
    // Do something eventually involving a call to String.Format(formatter, values);
}

Is there a way to tell if my values array has enough objects in it to cover the formatter, so that I can throw an exception if there aren't (short of doing the string.Format; that isn't an option until the end due to some lambda conversions)?

A: 

Use a regex to count the number of templates, but be careful, because

string.Format("{0}{0}", 123)

is valid.

You really need to provide more info for this question to be answered ok...

gmagana
And {{ }} mean replace with single braces.
jm
A: 

You could do a RegEx for the brace formatters and then compare them to the length of the value array.

Dan Vallejo
I don't think regex is a very robust solution. For example, imagine all the possible placeholders you could have in a formatting string, like `{0:yyyy-MM-dd}` or escaped braces `{{{0} {1}}}` which would make a regex cry and fail.
Skurmedel
+3  A: 

I'm still not clear why you think you cannot use string.Format to test it. If the passed in formatter is supposed to have placeholders for the items in values, then you should be able to do this:

static void TestFormat(string formatter, params string[] values)
{
    try
    {
        string.Format(formatter, values);
    }
    catch (FormatException e)
    {
        throw new Exception("the format is bad!!", e);
    }
}

Sample Usage:

        TestFormat("{0}{1}{2}", "a", "b", "c"); // works ok
        TestFormat("{0}{1}{2}", "a", "b"); // throws exception
        TestFormat("{0}{1}{2}}0{", "a", "b", "c"); // throws exception

Trying to do this with a regular expression is going to be tough, because what about something like this:

"{0}, {1}, {abc}, {1a4} {5} }{"

{abc} and {1a4} aren't valid for string.Format, and you also have to determine for each valid number ({0}, {1}, {5}) that you have at least that many arguments. Also, the }{ will cause string.Format to fail as well.

I just used the former approach described above in a recent project and it worked great.

dcp
How does this answer the question? I can think of several reasons why you'd need to know how many tokens need to be filled. You may want to fill them w/ different values based on the number of tokens available. Think of the way the asp.net mvc webform view-engine uses strings for finding views. That's a valid use, no?
Esteban Araya
I suppose I can use string.Format to test the values initially even if the input types aren't what I'll eventually use to format the string. The number of items will match in both cases. Apologies for the poorly written question.
sdanna
@Estaban Araya - Refer to the OP: "Is there a way to tell if my values array has enough objects in it to cover the formatter". That is what the above solution does, and I provided examples to prove it. I don't know what else you are expecting here. Obviously, it solved the OP's problem since they accepted it.
dcp
@dcp: The fact that the OP accepted your question has no bearing on the correctness of your answer nor its quality.string.Format("{0}-{1}") does not throw an exception and does not tell you anything about the number of tokens to be filled.
Esteban Araya
@Esteban Araya - You are wrong. string.Format("{0}-{1}") **does** throw an exception. Didn't you test it yourself before posting that?
dcp
+2  A: 

I think you are worrying too much about this. If the format string is invalid, let string.Format throw the exception for you. If you do not want a FormatException to be thrown, catch it and throw the exception you want.

It should also not really be a problem that you have already done some some processing (eg. evaluating lambda conversions) because this is after all an exceptional circumstance (with possibly the exception that the lambdas are very costly, in which case do the string.Format test first without processing the arguments to check it is valid and then repeat it when you need to later after the processing).

adrianbanks
True, it is an exceptional case. If it was code I was writing for myself, I would probably use this approach because well... I know how it works because I wrote it. One of the additional inputs is a list and I'm writing this method with other developers in mind, so being able to quick return would be my ideal solution in this case due to not knowing how the method will be used.
sdanna