【问题标题】:Check a condition before each line of code without multiple IF statements?在没有多个 IF 语句的情况下检查每行代码之前的条件?
【发布时间】:2013-08-29 14:42:35
【问题描述】:

是否可以检查语句块的每一行的条件是否为真,而无需在每行之前添加if (condition)

例如:

if (condition)
{
    DoSomething();
    DoSomethingElse();
    DoAnotherThing();
}

在某个时刻,另一个后台进程可能在执行DoSomethingElse() 之前将condition 设置为false。本质上,我正在寻找一种有效且更简单的说法:

if (condition) DoSomething();
if (condition) DoSomethingElse();
if (condition) DoAnotherThing();

实际上,这是一段很长的代码,执行一次,如果在任何时候更改了特定标志,我想放弃它。

收紧此类代码的最佳方法是什么。

【问题讨论】:

  • 多态性。创建表示实体 DoSomething()、DoSomethingElse() 和 DoAnotherThing() 的类。然后调用 myclass1.doThing(); myclass2.doThing() 和 myclass3.doThing()。在这些方法中,重定向到单个方法,该方法检查条件,然后运行适当的函数。 sourcemaking.com/refactoring/…
  • 如果,否则如果,如果,否则...?

标签: c# if-statement redundancy


【解决方案1】:

否 - 将检查一次条件,然后执行整个块。另一种选择可能是在块中注入救助:

if (condition)
{
    DoSomething();
    if(!condition) return;
    DoSomethingElse();
    if(!condition) return;
    DoAnotherThing();
}

另一种方法是,如果函数可以参数化,以便您可以将它们放入循环中:

foreach (varmyParam in parameters)
{
    if(condition)
       DoSomething(myParam);
}

编辑

再想一想这可能是你最好的选择:

List<Action> funcs = new List<Action> {DoSomething, DoSomethingElse, DoAnotherThing};
foreach( Action a in funcs)
{
   if(condition) a();
}

这要求所有方法都具有相同的签名(在您的情况下返回 void 不带参数),但它更简洁。

【讨论】:

  • 这是一个比检查每一行更好的选择,我认为这是我必须要做的!
  • 你到底是如何从这样的 if 语句中使用 break 的?
  • Return 可能无法正常工作,因为代码块可能不在方法中。
  • 你也可以使用var funcs = new[]{ ... },它更短(当它们仅用于foreach时,没有理由将它们装箱在List中)
【解决方案2】:

封装支票,也许?

if(condition)
    DoSomething(condition);

DoSomething内部

if(condition)
{
    // do your stuff inside method.
}

意思是你的代码现在看起来像:

DoSomething(condition);
DoSomethingElse(condition);

【讨论】:

  • IMO,这不适用于方法名称。如果我执行DoSomething,我希望它能够做一些事情。没什么。它也只是解决问题。
  • 会的;你是对的。但 OP 正试图清除该代码。通过将一个块中的三个 if 语句传播到三个块中的一个 if 语句,它肯定看起来更干净。虽然同意方法名称。
【解决方案3】:

您可以将其包装在 try/catch 块中,并在更改标志时在每个方法内引发异常:

try 
{
    DoSomething();
    DoSomethingElse();
    DoAnotherThing();
}
catch (FlagChangedException e)
{
    // do something to handle it
}

【讨论】:

  • 您不应将try catch 用于预期的正常程序流程。 try catch 用于解决意外的不可恢复问题。
  • 我相信其目的是在单独的线程上运行此代码
【解决方案4】:

可能是这样的:

int step = 1;
bool running = true;

while (running && condition) {
   switch (step) {
      case 1: DoSomething(); break;
      case 2: DoSomethingElse(); break;
      case 3: DoAnotherThing(); break;
      // and maybe other cases
      default: running = false; break; // AFAIK you can't break out of both switch and while (without labels)
   }

   step = step + 1;
}

【讨论】:

  • 对我来说,这似乎更长,更令人困惑,然后只是重复 if(condition) 每一行
  • 我并没有说这是完美的解决方案,只是一种可能性:-)
【解决方案5】:

您可以将它包装在一个委托方法中,调用带有您的条件的方法以及您想要执行的方法(如果它为真)。你甚至可以用一个函数列表来做到这一点:

void Main()
{
   DoSomething();
   DoIf(true, DoWork1);
   DoIf(false, DoWork2);
   var MyFunctions = new List<MyFunction>() { DoWork1, DoWork2 };

   foreach(var func in MyFunctions) {
       DoIf(someBoolCondition == 0, func);
   }
}

public delegate void MyFunction();

void DoSomething() {
   Console.WriteLine("Always");
}

public void DoWork1() {
    Console.WriteLine("Only if it was true");
}

public void DoWork2() {
   Console.WriteLine("Only if it was true");
}

void DoIf(bool condition, MyFunction function) {
   if(condition) {
       function();
   }
}

输出:

Always
Only if it was true

【讨论】:

    【解决方案6】:

    您可以将 lambda 与 Action 一起使用,但这并不能真正节省大量输入:

    Action<Action> exec = a => { if (condition) a(); };
    
    exec(DoSomething);
    exec(DoSomethingElse);
    exec(DoAnotherThing);
    

    【讨论】:

      【解决方案7】:

      听起来您正在使用多个线程 - 一个线程来完成工作,而另一个线程可以取消工作请求。

      如果是这种情况,您应该考虑只是中止执行工作的线程而不是设置一些标志。查看http://msdn.microsoft.com/en-us/library/System.Threading.Thread.Abort.aspx

      这非常简单,并且可以让标志检查出您的工作线程。

      Thread.Abort 的一个重要假设是在任务中间中止工作方法是安全的。您当前的标志检查解决方案允许当前执行的方法在放弃其余工作之前完成 - 所以请记住这一点。

      【讨论】:

      • 我强烈建议不要将 thread.abort 用于这么简单的事情。 stackoverflow.com/questions/421389/…
      • 我们不知道它有多简单 - OP 只是一个虚拟示例,但指的是更大的代码块。
      • @Moop - 您的参考资料显示了 Thread.Abort 的一个特别糟糕的情况,但我不会让这决定避免 Thread.Abort 的一切......
      猜你喜欢
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      • 2012-11-30
      • 2013-03-27
      • 2012-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多