c#在switch语句中执行所有情况

本文关键字:情况 执行 switch 语句 | 更新日期: 2023-09-27 18:13:11

我有一个像下面这样的开关语句:

switch(task)
    {
        case 1:
            print();
            break;
        case 2:
            save();
            break;
        case 3:
            sendmail();
            break;
    }

我需要一种方法来执行所有情况,这意味着如果task是(all)我想打印,保存和发送邮件。在给定的情况下使用一些修改是否可行我知道,我可以这样做:

case All:
    print();
    save();
    sendmail();
    break;

但是就像我说的,我想知道,在switch语句中是否有一种方法可以执行所有的case。提前感谢

c#在switch语句中执行所有情况

回答你的实际问题:

表示在switch语句中有一种方法可以执行所有情况。

这可不是我能想到的干净的方法。


我建议稍微改变一下模式,让task成为一个标志enum

[Flags]
public enum TaskOptions 
{
    Print    = 1,
    Save     = 2,
    SendMail = 4,
    //Note that these numbers go up in powers of two
}

你可以这样做:

task = TaskOptions.Print | TaskOptions.Save;
if (task.HasFlag(TaskOptions.Print))
{ 
    print();
}
if (task.HasFlag(TaskOptions.Save))
{ 
    save();
}
if (task.HasFlag(TaskOptions.SendMail))
{ 
    sendMail();
}

您不再需要显式地担心all


如果你想添加一个新选项

[Flags]
public enum TaskOptions 
{
    Print    = 1,
    Save     = 2,
    SendMail = 4,
    NewOption = 8,
}
task = TaskOptions.Print | TaskOptions.Save;
if (task.HasFlag(TaskOptions.Print))
{ 
    print();
}
if (task.HasFlag(TaskOptions.Save))
{ 
    save();
}
if (task.HasFlag(TaskOptions.SendMail))
{ 
    sendMail();
}
if (task.HasFlag(TaskOptions.NewOption))
{ 
    newOption();
}

Jaymee要求澄清|&

请解释一下task = TaskOptions的语法。打印| TaskOptions.Save。不确定这里的管道的使用,我认为这是"或",但这里没有评估!?事实上,对于单个&符号也是如此——在

之前从未见过这样使用它

这些是位操作符。它们逐位比较两个数字并返回结果。

在我们的示例中,我们使用了4个标志,每个标志由一个布尔值表示。一个布尔值可以用一个位来表示。

让我们使用以下缩写:

Print = P
Save = S
SendMail = M
NewOption = N
8  4  2  1
N  M  S  P

我以task = TaskOptions.Print | TaskOptions.Save为例

0  0  0  1   P is declared as 1 in the enum. 
0  0  1  0   S is declared as 2 in the enum.
========== 
0  0  1  1   < I've "or'd" these numbers together. They now represent Print AND Save as one option. The number "3" (binary 0011) is equivalent to "print and save"

当我有"3",我想知道它是否包含一个特定的标志,我&与该标志。

N  M  S  P
0  0  1  1  //This is P & S
0  0  0  1  //And we want to check if it has "P"
==========
0  0  0  1  < this returns non-zero. it contains the flag!

我们对N

做同样的处理
N  M  S  P
0  0  1  1  //This is P & S
1  0  0  0  //And we want to check if it has "N"
==========
0  0  0  0  < this returns zero. This state doesn't contain "N"
编辑:David Arno

要添加到这个答案中,而不是使用一系列if s,可以使用Dictionary和for循环:

private readonly Dictionary<TaskOptions, Action> actions =
    new Dictionary<TaskOptions, Action>
    {
        { TaskOptions.Print, Print },
        { TaskOptions.Save, Save },
        { TaskOptions.SendMail , SendMail }
    };
...
var task = TaskOptions.Print | TaskOptions.Save;
foreach (var enumValue in Enum.GetValues(typeof(TaskOptions)).Cast<TaskOptions>())
{
    if (task.HasFlag(enumValue))
    {
        actions[enumValue]();
    }
}

尝试添加一个具有特殊行为的单独类,因为这比破解switch语句更清楚:

class FallSwitch 
{
     SortedDictionary<int, Action> _cases = new SortedDictionary<int, Action>();
    public void AddCaseAction(int @case, Action action)
    {
        if (_cases.ContainsKey(@case)) throw ArgumentException("case already exists");
        _cases.Add(@case, action);
    }
    public void Execute(int startCase)
    {
        if (!_cases.ContainsKey(startCase)) throw ArgumentException("case doesn't exist");
        var tasks = _cases.Where(pair => pair.Key >= startCase);
        tasks.ForEach(pair => pair.Value());
    }
}

并像这样使用:

var fs = new FallSwitch();
fs.AddCaseAction(0, () => Console.WriteLine("0"));
fs.AddCaseAction(1, () => Console.WriteLine("1"));
fs.AddCaseAction(2, () => Console.WriteLine("2"));
fs.AddCaseAction(6, () => Console.WriteLine("6"));
fs.Execute(1);

按要求评论作为答案。

也许你应该考虑使用一个flags枚举并创建一个Dictionary。您可以对所有枚举值使用foreach-loop,检查条目是否可用并执行该方法。因此,在这种情况下,需要开关。

[Flags]
public enum TaskOptions 
{
    Print    = 1,
    Save     = 2,
    SendMail = 4
}
// In the clase where print(), save() and sendmail() are declared
private readonly Dictionary<TaskOptions, Action> _tasks;
public Ctor()
{
    _tasks = new Dictionary<TaskOptions, Action>
        {
            { TaskOptions.Print, this.print },
            { TaskOptions.Save, this.save },
            { TaskOptions.SendMail, this.sendmail }
        };
}
public void Do(TaskOptions tasksToRun)
{
    foreach (var action in from taskOption in Enum.GetValues(typeof(TaskOptions)).Cast<TaskOptions>()
                           where tasksToRun.HasFlag(taskOption)
                           orderby taskOption // only to specify it in the declared order
                           select this._tasks[taskOption])
    {
        action();
    }
}

但是你已经得到了一个答案,用一个干净的策略模式做了同样的事情。这或多或少是相同的,但使用委托代替类。

正如你所知道的,在c#中,漏穿并不是隐式发生的,而是goto被扩展为允许case标签作为目标标签,这样漏穿就可以显式地发生。

简单地让你的"all"值匹配第一个标签,然后继续goto下一个,如果它的值:

switch(task)
{
  case 1: case 0;//I don't know what "all" is, so I'm using 0 here
    print();
    if (task == 0) goto case 2;
    break;
  case 2:
    save();
    if (task == 0) goto case 3;
    break;
  case 3:
    sendmail();
    break;
}

您可以尝试更面向对象的方法。定义一组类,每个类负责执行一种类型的任务。当您想要运行多个任务时,只需将单个任务排队即可。使用switch语句非常不灵活。想象一下,有一天添加了第四个任务,然后还想要一个选项来运行任务1、2和;

 RunTasks(new[] {new PrintTask(), new SaveTask(), new SendMailTask()});
 void RunTasks(int[] tasks)
 {
     foreach (var task in tasks)
     {
         task.Run();
     }
 }
 interface ITask
 {
     void Run();
 }
 class PrintTask : ITask
 {
      public void Run()
      {
          ....
      }
  }
  // etc...

您可以创建一个像这样的新case

switch(task)
{
    case 1:
        print();
        break;
    case 2:
        save();
        break;
    case 3:
        sendmail();
        break;
    case 4:
        print();
        save();
        sendmail();
        break;
}

或者你可以设置默认的case来执行所有的case

 switch(task)
{
    case 1:
        print();
        break;
    case 2:
        save();
        break;
    case 3:
        sendmail();
        break;
    default:
        print();
        save();
        sendmail();
        break;
}

这两种方法都不是很简洁,但我认为它们可能是解决你问题的最简单的方法。