Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#执行switch语句中的所有情况_C#_Loops_Switch Statement_Case - Fatal编程技术网

C#执行switch语句中的所有情况

C#执行switch语句中的所有情况,c#,loops,switch-statement,case,C#,Loops,Switch Statement,Case,我有一个switch语句,如下所示: switch(task) { case 1: print(); break; case 2: save(); break; case 3: sendmail(); break; } 我需要一种方法来执行所有案例,这意味着如果任务是(全部) 我想打印、保

我有一个switch语句,如下所示:

switch(task)
    {
        case 1:
            print();
            break;
        case 2:
            save();
            break;
        case 3:
            sendmail();
            break;
    }
我需要一种方法来执行所有案例,这意味着如果任务是(全部) 我想打印、保存和发送邮件。 对给定情况进行一些修改是否可行 我知道,我可以做到以下几点:

case All:
    print();
    save();
    sendmail();
    break;
但正如我所说的,我想知道switch语句中是否有一种方法可以执行所有情况。 提前感谢

如您所知,在C#中,故障不会隐式发生,而是扩展了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语句中有方法执行所有情况

我想不出一个干净的方式


我建议稍微改变一下模式,把
task
a改为

然后,您可以执行以下操作:

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.Print | 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"
让我们为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"

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

 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...

尝试添加一个具有特殊行为的单独类,因为它比破解
开关
语句更清晰:

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());
    }
}

你可以创建一个这样的新案例

switch(task)
{
    case 1:
        print();
        break;
    case 2:
        save();
        break;
    case 3:
        sendmail();
        break;
    case 4:
        print();
        save();
        sendmail();
        break;
}
或者,您可以将默认案例设置为执行所有案例

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

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

如要求,请将评论作为答案


也许你应该考虑使用标志枚举并创建一个字典。您可以在所有枚举值上使用foreach循环,检查条目是否可用并执行该方法。因此,在这种情况下需要切换

[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();
    }
}
[标志]
公共枚举任务选项
{
Print=1,
Save=2,
SendMail=4
}
//在声明print()、save()和sendmail()的类别中
专用只读字典任务;
公职人员()
{
_任务=新字典
{
{TaskOptions.Print,this.Print},
{TaskOptions.Save,this.Save},
{TaskOptions.SendMail,this.SendMail}
};
}
public void Do(任务选项tasksToRun)
{
foreach(Enum.GetValues(typeof(TaskOptions)).Cast()中from taskOption中的var action)
其中tasksToRun.HasFlag(taskOption)
orderby taskOption//仅在声明的顺序中指定它
选择此选项。\u任务[任务选项])
{
动作();
}
}

但你已经得到了一个答案,使用干净的策略模式也能做到这一点。这或多或少是相同的,但是使用委托而不是类。

也许你应该考虑使用标志枚举并创建<代码>字典< /代码>。您可以在所有枚举值上使用foreach循环,检查条目是否可用并执行该方法。因此,在这种情况下需要切换。我不打算将此作为答案发布。但是,当你给这些条件的流程增加复杂性时,它的可读性就会降低。例如,只需将其拆分并多次调用
print()
。谢谢您的回答,但如果我有5个案例:)而不是3然后只需向枚举添加更多案例:
Option4=8,Option5=16
,并重复
if
s
task.haskag(TaskOptions.NewOption)的模式
您可以通过用
字典替换
if
系列来改进此答案。除此之外,这是一个很好的答案。您可以将所有任务通过管道连接在一起,如
task=TaskOptions.Print | TaskOptions.Save | TaskOptions.SendMail
或使用数学:
task=2^(numofTasks)-1
。在这种情况下,所有
都是1,并对应于所有选项。@modiX从未在语言中使用标准的习惯用法来表示故障?为什么?(请告诉我,你不是基于迪克斯特拉1968年写的东西。这四个字母的特殊用法在1968年并不存在)。事实上,我没有使用
GOTO
,我使用的是
GOTO
。@jonhana——迪克斯特拉所说的仍然有效。用
goto
控制流是可怕的。案例2中的
如果任务==0
条件将永远不会计算为真。这是一个可怕的语言功能,因为您正在重新发明命令模式控制盘。C#已经有了
动作
,它更简洁地覆盖了模式,而不必创建大量高度重复的类。回答得好。不过有一件小事:我认为另一个答案使用的是GoF风格的命令模式,而不是策略模式。我对“clean”也有异议,因为代理是这两种模式的更干净的实现。
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);
switch(task)
{
    case 1:
        print();
        break;
    case 2:
        save();
        break;
    case 3:
        sendmail();
        break;
    case 4:
        print();
        save();
        sendmail();
        break;
}
 switch(task)
{
    case 1:
        print();
        break;
    case 2:
        save();
        break;
    case 3:
        sendmail();
        break;
    default:
        print();
        save();
        sendmail();
        break;
}
[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();
    }
}