在switch语句中使用字符串集合

Phi*_*p M 11 c# arrays string switch-statement

我正试图找到解决这个问题的方法.这是我的示例代码:

class Program
{
  private string Command;

  private static string[] Commands = { "ComandOne", "CommandTwo", "CommandThree", "CommandFour" };


  static void Main(string[] args)
  {
    Command = args[0];
    switch(Command)
    {
      case Commands[0]: //do something 
        break;
      case Commands[1]: //do something else
        break;
      case Commands[2]: //do something totally different
        break;
      case Commands[3]: //do something boring
        break;
      default: //do your default stuff
        break;
    }
  }

  void DifferentMethod()
  {
    foreach(string c in Commands)
    {
      //do something funny
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

此代码不起作用,因为switch中的字符串值不是常量.我想编写易于维护的代码.
我喜欢使用类似数组的东西,因为我需要在循环中的其他地方使用相同的值.
使用int值,枚举将是完美的,但我没有找到与字符串相同的小解决方案.

Kir*_*oll 19

转换Commands为枚举:

enum Commands { ComandOne, CommandTwo, CommandThree, CommandFour }
Run Code Online (Sandbox Code Playgroud)

Switch语句应如下所示:

static void Main(string[] args)
{
    Command = (Commands)Enum.Parse(typeof(Commands), args[0]);
    switch(Command)
    {
        case Commands.CommandOne: 
            //do something 
            break;
        case Commands.CommandTwo: 
            //do something else
            break;
        ...
        default:
            // default stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

你的最后一个方法应该是这样的:

void DifferentMethod()
{
    foreach(var c in Enum.GetValues(typeof(Commands)))
    {
        string s = c.ToString(); 
        //do something funny
    }
}
Run Code Online (Sandbox Code Playgroud)


Ani*_*Ani 8

在您的具体示例中轻松修复:

switch(Array.IndexOf(Commands, Command))
{
    case 0: ...  
    case 1: ...

    default: //unknown command. Technically, this is case -1
} 
Run Code Online (Sandbox Code Playgroud)

其他替代品:

  1. 内联字符串.

    switch(命令){case"CommandOne":... case"CommandTwo":...}

  2. 正如KirkWoll所说,使用枚举.这可能是最干净的解决方案.

  3. 在更复杂的场景中,使用诸如Dictionary<string, Action>Dictionary<string, Func<Foo>>可能提供更好的可表达性的查找 .

  4. 如果案例很复杂,您可以创建一个ICommand界面.这将需要将命令字符串映射到正确的具体实现,为此您使用简单的构造(切换/字典)或花式反射(查找ICommand具有该名称的实现,或具有特定的属性修饰).

  • +1.使用Kirk的解决方案,OP可能会更好,但这更接近于显示他正在要求的方式. (3认同)

And*_*rey 5

就在昨天,我为它创建了一个解决方案.在你的情况下,enums更好,但这是我的一般非常规开关情况的解决方案.

用法:

    static string DigitToStr(int i)
    {
        return i
            .Case(1, "one")
            .Case(2, "two")
            .Case(3, "three")
            .Case(4, "four")
            .Case(5, "five")
            .Case(6, "six")
            .Case(7, "seven")
            .Case(8, "eight")
            .Case(9, "nine")
            .Default("");
    }

        int a = 1, b = 2, c = 3;
        int d = (4 * a * c - b * 2);
        string res = true
            .Case(d < 0, "No roots")
            .Case(d == 0, "One root")
            .Case(d > 0, "Two roots")
            .Default(_ => { throw new Exception("Impossible!"); });

        string res2 = d
            .Case(x => x < 0, "No roots")
            .Case(x => x == 0, "One root")
            .Case(x => x > 0, "Two roots")
            .Default(_ => { throw new Exception("Impossible!"); });

        string ranges = 11
            .Case(1, "one")
            .Case(2, "two")
            .Case(3, "three")
            .Case(x => x >= 4 && x < 10, "small")
            .Case(10, "ten")
            .Default("big");
Run Code Online (Sandbox Code Playgroud)

定义:

class Res<O, R>
{
    public O value;
    public bool succ;
    public R result;

    public Res()
    {

    }

    static public implicit operator R(Res<O, R> v)
    {
        if (!v.succ)
            throw new ArgumentException("No case condition is true and there is no default block");
        return v.result;
    }
}

static class Op
{
    static public Res<O, R> Case<O, V, R>(this Res<O, R> o, V v, R r)
    {
        if (!o.succ && Equals(o.value, v))
        {
            o.result = r;
            o.succ = true;
        }
        return o;
    }

    static public Res<O, R> Case<O, V, R>(this O o, V v, R r)
    {
        return new Res<O, R>()
        {
            value = o,
            result = r,
            succ = Equals(o, v),
        };
    }

    static public Res<O, R> Case<O, R>(this Res<O, R> o, Predicate<O> cond, R r)
    {
        if (!o.succ && cond(o.value))
        {
            o.result = r;
            o.succ = true;
        }
        return o;
    }

    static public Res<O, R> Case<O, R>(this O o, Predicate<O> cond, R r)
    {
        return new Res<O, R>()
        {
            value = o,
            result = r,
            succ = cond(o),
        };
    }

    private static bool Equals<O, V>(O o, V v)
    {
        return o == null ? v == null : o.Equals(v);
    }

    static public R Default<O, R>(this Res<O, R> o, R r)
    {
        return o.succ
            ? o.result
            : r;
    }

    static public R Default<O, R>(this Res<O, R> o, Func<O, R> def)
    {
        return o.succ ? o.result : def(o.value);
    }
}
Run Code Online (Sandbox Code Playgroud)


Bri*_*eon 5

你可以switch通过创建IYourCommand对象并将它们加载到一个完全消除语句Dictionary<string, IYourCommand>.

class Program
{
  private Dictionary<string, IYourCommand> Command = new Dictionary<string, IYourCommand>
    {
       { "CommandOne",   new CommandOne()   },
       { "CommandTwo",   new CommandTwo()   },
       { "CommandThree", new CommandThree() },
       { "CommandFour",  new CommandFour()  },
    };

  public static void Main(string[] args)
  {
    if (Command.ContainsKey(args[0]))
    {
      Command[args[0]].DoSomething();
    }
  }
}

public interface IYourCommand
{
  void DoSomething();
}
Run Code Online (Sandbox Code Playgroud)