views:

996

answers:

7

I've found what seems to be the C# equivalent of a FOR-CASE structure in a proyect I'm working on:

foreach (string param in params.Split(';'))
{
    string[] parts = param.Split('=');
    string key = parts[0].Trim().ToLower();
    string value = parts[1].Trim();
    switch (key)
    {
        case "param1": this.param1 = value; break;
        case "param2": this.param2 = value; break;
        case "param3": this.param3 = value; break;
        case "param4": this.param4 = value; break;
        default: break;
    }
}

(Variable names changed to protect the guilty.)

How would you implement this code?

+5  A: 

I don't think the code in your question is anything like the code you linked to....

The code in the question looks like something I might do if I wrote a command line tool.

Am I stupid for not seeing whats wrong with the code in the question?

An alternative is to use reflection to fill parameter value variables. I've done it that ways sometimes too.

BTW: I once wrote a program in a script language that had switch as the only flow control mechanism and no gosub/return. The code in my program was structured a bit like the one you linked to. A massive switch on a sort of instruction pointer variable that got reassigned at the end of every case and an almost infinite loop around the switch. It got the job done.

Guge
If I were doing this, I'd probably create a dictionary based on the input string, and assign the params from the dictionary: param1 = input_map["param1"];Sure, you'd have to catch a KeyNotFoundException, but the code would look cleaner IMHO.
Harper Shelby
I agree with your assesment
Nathan Koop
" I once wrote a program in a script language that had switch as the only flow control mechanism ..." Sounds like a 'C' Windows message pump.
John MacIntyre
@Harper - I try not to use dictionaries where I can use a class. My default in the switch can take care of telling the user that the key was unknown, as can I with the reflection solution. Also the " you would have to use to fetch from Dictionary<string, string> blinds the compiler.
Guge
@John - The language was called "BRS MNS". It was a menu system for a text database. I did it when I was 20. I'm still proud of it.
Guge
+3  A: 

I see you that you already have multiple fields in your class that you use to hold the variables. In that case, what you are doing is fine.

Otherwise, you can have 1 HashTable (maybe add in the C# indexor as a twist) to hold all of them, and your loop will end up like this:

foreach (string param in params.Split(';'))
{
    string[] parts = param.Split('=');
    string key = parts[0].Trim().ToLower();
    string value = parts[1].Trim();
    MyHashTable[key] = value;
}

The problem with this approach is that you should only have 1 type of value. For example, if your param list can contain both string and int types, it makes the code messier, especially you need to perform error checking and validation and stuff.

I personally would stick with what you already have.

Haoest
+1  A: 

Not sure if I understand either but it sounds like you're complicating yourself. Don't reinvent the wheel, use BCL classes as much as you can, these classes are proven to work efficiently and save you lots of time. Sounds like you could implement it with some sort of Dictionary<,> along with, like Guge suggested, Reflection.

Ricardo Villamil
It seems natural to me that way too.
leppie
+3  A: 

You could use reflection for this:

Type t = this.GetType();
foreach (string param in params.Split(';'))
{    
    string[] parts = param.Split('=');    
    string key = parts[0].Trim().ToLower();    
    string value = parts[1].Trim();    

    t.GetProperty(key).SetValue(this, value, null);
}
Jon B
I've done this a few times but I have always used a designated class, or marked available properties with a custom attribute.
Guge
Same here. I prefer using an attribute and an arbitrary key name or enum so I can rename my properties at will. However, I thought this example was best for the code sample provided.
Jon B
What happens if one of the passed values isn't a valid property name? The OP's code safely ignores bad params...
Coderer
@Coderer - you would want to add error handling or check that the property exists before trying to set it. My example is just meant to get the OP started, not to be complete production code.
Jon B
A: 

Or Regex:

string parms = "param1=1;param2=2;param3=3";
string[] parmArr = parms.Split(';');        

string parm1 = Regex.Replace(parmArr[0], "param1=", "");
string parm2 = Regex.Replace(parmArr[1], "param2=", "");
string parm3 = Regex.Replace(parmArr[2], "param3=", "");
Andrew Cowenhoven
Only works if the params are in that order. "param2=2;param3=3;param1=1" will fail, whereas the OP will handle it. And the "regex" portion is superfluous, as you're just doing a straight string replace.
GalacticCowboy
+2  A: 

For what it's worth, the WTF article was a WTF because its outer loop was completely useless, as noted in the article - it was just as easy, and more direct, just to set an index variable directly than to loop and test it.

GalacticCowboy
A: 

I actually think the OP's code is fine. It's not perfect -- there might be simpler or cleaner ways to do it, but it effectively allows for readable mappings between member/property names and input-parameter names. It leaves your properties strongly typed (unlike the hashmap/dictionary solutions, unless your class has only one type for all its properties...) and gives you one fairly-obvious place to fix or add mappings.

Coderer