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。提前感谢
回答你的实际问题:
表示在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;
}
这两种方法都不是很简洁,但我认为它们可能是解决你问题的最简单的方法。