简体   繁体   中英

How to use an array of strings to handle the cases in a switch statement in C#?

I have an array

    public static string[] commands =
    {   
        "command1",
        "command2",
        "command3",
        "command4",
        "command5",
        "command6",
        "command7"
    };

I want to use the array in the function

    public static bool startCommand (string commandName) {
        //stuff
        if (commandName == commands[0]) {
            //stuff
            return true;
        }
        else {
            //stuff
            switch (commandName) {
                case commands [1]:
                    //stuff
                    break;
                case commands [2]:
                    //stuff
                    break;
                case commands [3]:
                    //stuff
                    break;
                case commands [4]:
                    //stuff
                    break;
                case commands [5]:
                    //stuff
                    break;
                case commands [6]:
                    //stuff
                    break;
                default:
                    return false;
            }
            //do stuff
            return true;
        }
    }

The error that this is giving me is "A constant value is expected" for each of the cases.

I could use if and else statements, but I think the switch statement looks better for this.

Unless I've missed my mark, my array is of constant strings, so this should work. Any help would be appreciated. Sorry if this is a newb question, I've been programming with C# for about four days.

What you're looking for is the Dictionary<TKey, TValue> type. A Dictionary is basically a collection of Key-Value pairs, something we can take advantage of for what you're attempting to achieve.

Using the example you've given, the implementation would look like this:

Dictionary<string, Action> commandsDictionary = new Dictionary<string, Action>();
commandsDictionary.Add("Command1", () => Console.WriteLine("Command 1 invoked"));
commandsDictionary.Add("Command2", () => Console.WriteLine("Command 2 invoked"));

commandsDictionary["Command2"].Invoke();
// Command 2 invoked

As you'll have noticed, I've introduced the an Action delegate without any parameters.


To introduce a parameter, just specify it as a type argument, like this: Action<int>

Dictionary<string, Action<int>> commandsDictionary = new Dictionary<string, Action<int>>();
commandsDictionary.Add("Command1", (i) => Console.WriteLine("Command {0} invoked", i));

commandsDictionary["Command1"].Invoke(1);
// Command 1 invoked

If you want to return a value from the delegate you're invoking, use the Func delegate, an easy to remember rule with Func is that the last type parameter is always the type being returned, so Func<int, string> would be equivalent to a method with the following signature public string Foo(int i)

Dictionary<string, Func<int, string>> commandsDictionary = new Dictionary<string, Func<int, string>>();
commandsDictionary.Add("Command1", (i) => { return string.Format("Let's get funky {0}", i); });

string result = commandsDictionary["Command1"].Invoke(56963);
Console.WriteLine (result);
// Let's get funky 56963



Reference

I've added this section to aid those who do not yet know what a delegate is... it's all actually rather simple.


Delegates

A Delegate is a Type that represents references to methods . They're just like variables that you declare to reference objects, except instead of objects, they reference methods.

A delegate can be instantiated with a named method or an anonymous function such as a lambda expression (which is the type I've demonstrated above).


The Action Delegate

The Action Delegate has a return type of void and defines its signature with type parameters.

void Example()
{
    // Named method
    this.NamedActionDelegate = NamedMethod;
    this.NamedActionDelegate.Invoke("Hi", 5);
    // Output > Named said: Hi 5

    // Anonymous Function > Lambda
    this.AnonymousActionDelegate.Invoke("Foooo", 106);
    // Output > Anonymous said: Foooo 106
}

public Action<string, int> NamedActionDelegate { get; set; }
public Action<string, int> AnonymousActionDelegate = (text, digit) => Console.WriteLine ("Anonymous said: {0} {1}", text, digit);

public void NamedMethod(string text, int digit)
{
    Console.WriteLine ("Named said: {0} {1}", text, digit);
}

The Func Delegate

The Func Delegate is similar to the Action Delegate the difference being that Func never returns void and thus will always require at least 1 type argument and as mentioned earlier, the type argument specified last dictates the return type of the delegate.

void Example()
{
    // Named method
    this.NamedFuncDelegate = NamedMethod;
    string namedResult = this.NamedFuncDelegate.Invoke(5);
    Console.WriteLine (namedResult);
    // Output > Named said: 5

    // Anonymous Function > Lambda
    string anonyResult = this.AnonymousFuncDelegate.Invoke(106);
    Console.WriteLine (anonyResult);
    // Output > Anonymous said: 106
}

public Func<int, string> NamedFuncDelegate { get; set; }
public Func<int, string> AnonymousFuncDelegate = (digit) => { return string.Format("Anonymous said: {0}", digit); };

public string NamedMethod(int digit)
{
    return string.Format ("Named said: {0}", digit);
}

If you want to use the switch with the array commands, instead use of compare with the items of commands use the index statement like this:

public static string[] commands =
{   
    "command1",
    "command2",
    "command3",
    "command4",
    "command5",
    "command6",
    "command7"
};

public static bool startCommand(string commandName)
{
    var index = Array.IndexOf(commands, commandName);

    //stuff
    if (index == 0)  // commands[0]
    {
        //stuff
        return true;
    }
    else
    {
        //stuff
        switch (index)
        {
            case 1:  // commands[0]
                //stuff
                break;
            case 2:  // commands[2]
                //stuff
                break;
            case 3:  // commands[3]
                //stuff
                break;
            case 4:  // commands[4]
                //stuff
                break;
            case 5:  // commands[5]
                //stuff
                break;
            case 6:  // commands[6]
                //stuff
                break;
            default:
                return false;
        }
        //do stuff
        return true;
    }
}

To summarize as an answer, change it to something like this:

        Dictionary<string, Action> commands = new Dictionary<string,Action>();
        commands.Add("command1", () => {});
        commands.Add("command2", () => { });
        commands.Add("command3", () => { });

        Action action = null;
        commands.TryGetValue(commandName, out action);
        if (action != null) 
            action();

You can make your dictionary static, or possibly readonly if you want:

    static void Command1() { }
    static void Command2() { }

    static readonly Dictionary<string, Action> commands = new Dictionary<string, Action>(){
        { "command1", Command1 },
        { "command2", Command2 }
    };

Assuming you are ok with constant strings, what about defining a static class:

public static class COMMANDS 
{
    public const string COMMAND1 = "command1";
    public const string COMMAND2 = "command2";
    public const string COMMAND3 = "command3";
    public const string COMMAND4 = "command4";
    public const string COMMAND5 = "command5";
    public const string COMMAND6 = "command6";
    public const string COMMAND7 = "command7";
}

and then use it with the switch statement:

//stuff
if (commandName == COMMANDS.COMMAND1)
{
    //stuff
    return true;
}
else
{
    //stuff
    switch (commandName)
    {
        case COMMANDS.COMMAND2:
            //stuff
            break;
        case COMMANDS.COMMAND3:
            //stuff
            break;
        case COMMANDS.COMMAND4:
            //stuff
            break;
        case COMMANDS.COMMAND5:
            //stuff
            break;
        case COMMANDS.COMMAND6:
            //stuff
            break;
        case COMMANDS.COMMAND7:
            //stuff
            break;
        default:
            return false;
    }
    //do stuff
    return true;
}
using System;
using System.Reflection;

namespace CommandExample
{
    class Program
    {
        static void Main()
        {
            var cmdName = "Command1";

            // Create an instance of the command class using reflection
            Type type = Assembly.GetExecutingAssembly().GetType("CommandExample." + cmdName);
            if (type == null) { /* Cannot find command. Handle error */ }
            var cmd = Activator.CreateInstance(type) as ICommand;

            cmd.Exec();
        }
    }

    interface ICommand
    {
        void Exec();
    }

    class Command1 : ICommand
    {
        public void Exec()
        {
            Console.WriteLine("Executing Command1");
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM