C#执行switch语句中的所有情况
我有一个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(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
stask.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();
}
}