我有一个如下所示的开关语句:
switch(task)
{
case 1:
print();
break;
case 2:
save();
break;
case 3:
sendmail();
break;
}
我需要一种方法来执行所有情况,这意味着如果任务是(全部) 我想打印,保存和发送邮件。 是否可以在给定的情况下使用一些修改 我知道,我可以这样做:
case All:
print();
save();
sendmail();
break;
但正如我所说,我想知道,如果在switch语句中有一种方法可以执行所有情况。 提前致谢
答案 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;
}
这两种方式都不是很整齐,但我认为它们可能是解决您问题的最简单方法。