我有一个带有下一个逻辑的代码:如果某个布尔标志为真,则必须先执行两个代码片段中的一个,反之亦然。但是他们两个都必须永远执行。不幸的是,C#没有这方面的语义指令,如下所示:
if (condition) first
{
//Some code to execute first if condition is true
}
second
{
//Some code to execute first if condition is false
}
现在,我这样做:
if (condition)
{
//Code 1
//Code 2
}
else
{
//Code 2
//Code 1
}
这样的必要性很多,这会产生许多代码重复。可能有更好的解决方案吗?
答案 0 :(得分:3)
将代码放入单独的方法
public void MyMethod1
{
//first code goes here
}
public void MyMethod2
{
//second code goes here
}
if (condition)
{
MyMethod1();
MyMethod2();
}
else
{
MyMethod2();
MyMethod1();
}
这样您就不必复制方法中的代码了。
答案 1 :(得分:2)
您可以考虑编写如下方法:
public static void DoBoth(Action first, Action second, bool keepOrder)
{
if (keepOrder)
{
first();
second();
}
else
{
second();
first();
}
}
答案 2 :(得分:1)
我用“代码1”和“代码2”创建了两个方法,然后像第二个选项那样继续:
if (condition)
{
Code1(); Code2();
}
else
{
Code 2(); Code1();
}
您还可以通过操作或代理对此进行修改,具体取决于“代码1”和“代码2”。
答案 3 :(得分:1)
我同意@Steven Jeuris关于更愿意了解潜在原因的评论,因为它可能指向需要改进的设计决策。但是,如果你需要坚持使用你拥有的东西,我会建议一个代理队列,因为你暗示你的例子与实际代码库相比非常简单。如果没有,那么其他一个答案就可以了,但随着复杂性的增加,下面的内容可能更容易维护。
注意:我将此作为示例 - GetQueue的参数及其内部的逻辑可以根据您的实际情况而改进。
public Queue<Action> GetQueue(bool condition)
{
var toReturn = new Queue<Action>();
if (condition)
{
toReturn.Enqueue(DoWork1);
toReturn.Enqueue(DoWork2);
}
else
{
toReturn.Enqueue(DoWork2);
toReturn.Enqueue(DoWork1);
}
return toReturn;
}
public void MyExecutingMethod()
{
foreach (var action in GetQueue(true))
{
action();
}
}
public void DoWork1()
{
}
public void DoWork2()
{
}
答案 4 :(得分:1)
您应该尽可能避免代码重复。在你的情况下,基本的想法是尝试提取似乎不止一次的所有内容,并试图将它“放”到你只需要写一次的地方。
在您的情况下,请说我们有以下内容:
public void Bar()
{
...
if (condition)
{
//code for action 1
//code for action 2
}
else
{
//code for action 2
//code for action 1
}
...
}
public void Foo()
{
...
if (condition)
{
//code for action 1
//code for action 2
}
else
{
//code for action 2
//code for action 1
}
...
}
现在我们显然可以看到你在这里有一些代码重复。我们可以通过以下方式改进:
public void Bar()
{
...
if (condition)
{
Action1();
Action2();
}
else
{
Action2();
Action1();
}
...
}
public void Foo()
{
...
if (condition)
{
Action1();
Action2();
}
else
{
Action2();
Action1();
}
...
}
private void Action1()
{
//code for action 1
}
private void Action2()
{
//code for action 1
}
这看起来好多了(特别是如果Action1
代码和Action2
代码很长)。我们现在设法只编写Action1
和Action2
的代码,无论我们的代码中有多少Foo
或Bar
样式方法。但我们仍然可以做得更多。你可以看到我们仍在复制一些令人讨厌的冗长代码。所以我们可以更进一步,做到以下几点:
public void Bar()
{
...
DoAction(condition);
...
}
public void Foo()
{
...
DoAction(condition);
...
}
private void Action1()
{
//code for action 1
}
private void Action2()
{
//code for action 1
}
private void DoAction(bool condition)
{
if (condition)
{
Action1();
Action2();
}
else
{
Action2();
Action1();
}
}
现在,恕我直言看起来好多了。我们不仅仅设法编写Action1
和Action2
特定代码一次,我们现在也设法只编写那个讨厌的方法排序逻辑。
这对可读性和最重要的可维护性产生了巨大影响。例如,如果在Action1
中出现错误,您现在只需要在一个地方更改它。在原始实现中,您必须检查所有代码并在任何地方修复错误。
另外,想象一下方法排序依赖于业务规则,而你的客户端(哦,我的惊喜!)决定改变它们。使用最新的实现,您只需要在一个位置更改代码。
经验法则:尽可能避免代码重复,它会大大减少你输入的代码,以及你或者一些不良灵魂在不久的将来会遇到的麻烦。
答案 5 :(得分:0)
我将冒险猜测code1要么没有副作用,要么对类成员变量采取行动,在这种情况下,它们可以包含在返回void的方法中。然后,您可以按照以下方式执行某些操作:
...
if (condition)
DoWork(() => Code1(), () => Code2());
else
{
DoWork(() => Code2(), () => Code1());
}
...
private void Code1()
{
// Code 1
}
private void Code2()
{
// code 2
}
private void DoWork(Action action1, Action action2)
{
action1();
action2();
}
答案 6 :(得分:0)
我提出了另一个建议(伪代码)。
编辑:这取决于您的情况,您将采取哪种方法。这种方法的好处是简单性和灵活性。通过灵活性,我的意思是订单的决定现在与代码分开,因此您可以轻松地执行诸如添加新订单之类的操作,或者让订单以其他方式指定(例如,如果您现在想要将不同的订单与基于属性文件的不同用户)?
if(condition)
runOrder = [ "one", "two" ];
else
runOrder = [ "two", "one" ];
for(x=0; x<runOrder.length; x++)
{
codeToRun = runOrder[x];
switch(codeToRun)
{
Case "one": Code1();
Case "two": Code2();
}
}