0

I would like to evaluate a dynamic string value within a switch statement in C#.

For example:

int i = 0;
foreach (Item item in _Items)
{
    foreach (Field theField in doc.Form.Fields)
    {
        switch (theField.Name)
        {
            case "Num" + i++.ToString(): // Dynamic Evaluation?
                theField.Value = string.Empty;
                break;
        }
    }
}

I have 20 or so fields named Num1, Num2, etc. If I can do this all in one statement/block, I'd prefer to do so.

But the compiler complains that the case statements need to be constant values. Is there a way to use dynamic variables in the case statement so I can avoid repeating code?

I just thought I'd mention, the purpose of this method is to populate the fields in PDF form, with naming conventions which I can not control. There are 20 rows of fields, with names like "Num1" - "Num20". This is why string concatenation would be helpful in my scenario.

Shawn J. Molloy
  • 2,457
  • 5
  • 41
  • 59
  • The reason why you can't was discussed (debated?) in [C# switch statement limitations - why?](http://stackoverflow.com/questions/44905/c-sharp-switch-statement-limitations-why) I think [this answer](http://stackoverflow.com/a/45584/516797) sums it up best. – Sean U Jan 20 '12 at 17:49
  • Are you sure you don't want the `i++` outside the inner `foreach`? – TrueWill Jan 20 '12 at 17:52
  • The C# Switch Statement Limitations post answers my question perfectly. Thank so much! – Shawn J. Molloy Jan 20 '12 at 18:10

6 Answers6

12

No. This is simply part of the language. If the values aren't constants, you'll have to use if/else if or a similar solution. (If we knew more details about what you were trying to achieve, we may be able to give more details of the solution.)

Fundamentally, I'd question a design which has a naming convention for the fields like this - it sounds like really you should have a collection to start with, which is considerably easier to work with.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • First off - I'm completely honored to receive an answer from you Jon. I've just purchased C# in Depth Second Edition, and finally feel like I'm crossing over from being a mediocre developer (one with enough knowledge to be dangerous) to a true professional. Amazing book! I'm in complete awe over your apparent love of the inter-workings of the .NET runtime, C# and I truely appreciate your passion. /end gushing comments. Thanks! – Shawn J. Molloy Jan 20 '12 at 18:09
  • I just want to quickly add - for anyone reading this, I can't put enough stress on how great C# In Depth is. There is simply nothing else like it out there - the only book I can compare it to in the quality of authorship is "JavaScript - The Good Parts" by douglas crockford. – Shawn J. Molloy Jan 20 '12 at 18:15
  • @Shawn: You're very kind :) Hope this answer was actually helpful to solving your problem as well, of course... – Jon Skeet Jan 20 '12 at 19:46
1

Yes case value must be able to be evaluated at compile time. How about this instead

foreach (Field theField in doc.Form.Fields)
{
    if(theField.Name == ("Num" + i++))
    {
        theField.Value = string.Empty;
    }
}
Ash Burlaczenko
  • 24,778
  • 15
  • 68
  • 99
0

Also consider that every time you concatenate two or more strings together the compiler will create memory variables for each of the component strings and then another one for the final string. This is memory intensive and for very large strings like error reporting it can even be a performance problem, and can also lead to memory fragmentation within your programs running, for long-running programs. Perhaps not so much in this case, but it is good to develop those best-practices into your usual development routines.

So instead of writing like this:

"Num" + i++.ToString()

Consider writing like this:

string.Format("{0}{1}", "Num", i++.ToString());

Also you may want to consider putting strings like "Num" into a separate constants class. Having string constants in your code can lead to program rigidity, and limit program flexibility over time as your program grows.

So you might have something like this at the beginning of your program:

using SysConst = MyNamespace.Constants.SystemConstants;

Then your code would look like this:

string.Format("{0}{1}", SysConst.Num, i++.ToString());

And in your SystemConstants class, you'd have something like this:

/// <summary>System Constants</summary>
public static class SystemConstants
{
    /// <summary>The Num string.</summary>
    public static readonly string Num = @"Num";
}

That way if you need to use the "Num" string any place else in your program, then you can just use the 'SysConst.Num'

Furthermore, any time you decide to change "Num" to "Number", say perhaps per a customer request, then you only need to change it in one place, and not a big find-replace in your system.

Seth Eden
  • 1,142
  • 2
  • 20
  • 42
0

How about:

int i = 0;
foreach ( Item item in _Items )
    doc.Form.Fields.First(f=>f.Name == "Num" + i++.ToString()).Value = string.Empty;

Not sure what the purpose of item is in your code though.

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
0

No. There is no way.

How about replacing the switch with:

if (theField.Name.StartsWith("Num"))
  theField.Value = string.Empty;

or some similar test?

Krizz
  • 11,362
  • 1
  • 30
  • 43
0
var matchingFields =
    from item in _Items
    join field in doc.Form.Fields
      on "Num" + item.PackageCount equals field.Name
    select field;

foreach (var field in matchingFields)
{
    field.Value = string.Empty;
}

For more efficiency include a DistinctBy on field Name after getting the matching fields (from MoreLINQ or equivalent).

TrueWill
  • 25,132
  • 10
  • 101
  • 150