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

时间:2015-09-17 09:36:57

标签: c# loops switch-statement case

我有一个如下所示的开关语句:

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

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

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

但正如我所说,我想知道,如果在switch语句中有一种方法可以执行所有情况。 提前致谢

6 个答案:

答案 0 :(得分:9)

回答你的实际问题:

  

如果switch语句中有一种方法可以执行所有情况。

不是我能想到的干净方式。

我建议稍微更改模式,而不是task flag 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.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"

当我有&#34; 3&#34;我想知道它是否包含一个特定的标志,我&带有那个标志。

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,可以使用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]();
    }
}

答案 1 :(得分:1)

尝试添加一个具有特殊行为的单独类,因为它比攻击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);

答案 2 :(得分:1)

按要求将评论作为答案。

也许你应该考虑使用flags枚举并创建一个Dictionary。您可以对所有枚举值使用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();
    }
}

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

答案 3 :(得分:0)

正如您所知,在C#中,不会隐式发生直通,而是public class Class1 { public event Action<string> Event; public Class1() { } public void DoSomething(string msg) { var handle = Event; if (handle != null) { handle(msg); } } } public class Class2 { private List<Class1> _class1s; public Class2() { _class1s = new List<Class1>(); } public void AddClass1Instance() { var newClass1Instance = new Class1(); newClass1Instance.Event += OnClass1DoSomething; _class1s.Add(newClass1Instance); } public void RemoveLastClass1Instance() { if(_class1s.Count > 0) { _class1s.RemoveAt(_class1s.Count - 1); } } private void OnClass1DoSomething(string msg) { } } 被扩展为允许案例标签成为目标标签,以便明确地落实。

只需让您的“所有”值与第一个标签匹配,然后继续goto下一个标签,如果值是:

goto

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

您可以像这样创建一个新案例

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

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