令我困扰的是空的/**/支架。有没有更干净的方法来处理这种逻辑?

if (opcode == OP_0) { /* continue */}
    else if (opcode == OP_1NEGATE) { /* continue */}
    else if (opcode >= OP_1 && opcode <= OP_16) { /* continue */}
    else { throw new Exception("decodeFromOpN called on non OP_N opcode"); }


评论

我看到大多数答案都复制了问题的缩进。我希望else if链与初始if对齐。当我看到一个缩进的其他字符时,我倾向于开始在同一水平上寻找if。通常,仅在控制结构内缩进一次,但将控制结构关键字保持在其开始的级别。

#1 楼

您可以使用的是一个返回操作码是否有效的函数。

private boolean isOpCode(Object opCode){
    return opcode == OP_0 || opcode == OP_1NEGATE || (opcode >= OP_1 && opcode <= OP_16);
}


然后在您发布的代码中调用该函数,如果返回则抛出异常错误。

if(!isOpCode(opCode)){
    throw new OpCodeInvalidException("decodeFromOpN called on non OP_N opcode");
}


用任何操作码替换Object

并创建一个从Exception扩展的新类。抛出Exception通常是不好的做法。

评论


\ $ \ begingroup \ $
应该使用条件OR运算符(||)代替按位逻辑OR运算符(|)。从语义上讲,它更接近含义,可以将其短路以避免避免评估整个表达式。
\ $ \ endgroup \ $
–马克·拉卡塔(Mark Lakata)
2014年3月11日下午4:59

\ $ \ begingroup \ $
我在这里看到很多冗余。为什么要检查每个操作码以查看是否存在这种操作码,而又要循环浏览一次以查找其执行的动作?切换似乎更加简单。
\ $ \ endgroup \ $
– Liamdev631
2014年3月12日在2:43

\ $ \ begingroup \ $
@ Liamdev631,我同意您的想法,对所有操作码进行switch声明,然后从那里开始。但是,他要求一种更简洁的逻辑处理方式。另外,如果OP _ ???是整数,则调用isOpCode运行相对较快。
\ $ \ endgroup \ $
–凯拉
2014年3月12日在20:08

#2 楼

仅当所有其他条件都为false时,才能执行else分支:

if (opcode != OP_0
  && opcode != OP_1NEGATE
  && (opcode < OP_1 || opcode > OP_16))
{
    throw ...;
}


#3 楼

我不喜欢if语句后的空白块。这非常令人困惑,并且使您的代码混乱。

我也不喜欢您抛出了一般的Exception。创建一个并抛出该异常。

public class InvalidOpCodeException : Exception
{
    private int OpCode { get; private set; }

    public InvalidOpCodeException(int opCode)
        : base(string.Format("OpCode supplied is invalid {0}.", opCode)
    {
        OpCode = opCode;
    }

}


我将其更改为仅查找错误情况

if (opcode != OP_0
    && opcode != OP_1NEGATE
    && (opcode < OP_1 || opcode > OP_16))
{
     throw new InvalidOpCodeException(opcode);
}

// Rest of the code here


#4 楼

使用switch语句可能会更有效,如果操作码没有语句,则抛出异常。

switch (opcode)
{
    case OP_0: { /* do stuffs */}
    case OP_1NEGATE: { /* do other stuffs */}
    ....
    default: { throw new Exception("a no no"); }
}


#5 楼

我将假设OP_0 ... OP_16是连续的,并且OP_0是最小的可能值。在这种情况下,将条件折叠在一起很简单:

if (opcode > OP_16 && opcode != OP_1NEGATE)
   throw new Exception("decodeFromOpN called on non OP_N opcode");


但是,如果OP_0可能与OP_1不连续,或者可能小于OP_0的值,则可能失败。

#6 楼

如果您将这三种情况分开是因为操作码值/范围表示不同的事情,并且出于不同的原因而选择了相同的动作(接受/跳过),那么我认为您的风格很好。描述每个案例含义的注释对于下一个人阅读代码很有用:

if (opcode == OP_0) { /* OP_0 (zero) is a no-op, ok */}
    else if (opcode == OP_1NEGATE) { /* flip register value */}
    else if (opcode >= OP_1 && opcode <= OP_16) { /* known allocated opcodes */}
    else { throw new Exception("decodeFromOpN called on non OP_N opcode"); }


通过这种方式,很明显案例在编写时具有不同的含义。 。随着代码的发展,将来的维护者可以在案例含义改变时添加/细分/合并案例,并且/或者在必要时针对每个案例添加调试信息或更改操作。

但是,每个人的回答,如果案例在此代码的本地上下文中具有大致相同的含义,则合并条件是有意义的。

评论


\ $ \ begingroup \ $
如果以几种方法执行相同的测试序列,并且每种情况都有语义[可能是显式的无操作],则这种设计可能特别好。例如,如果代码基于操作模式选择一系列if语句,则可以将“切换到XXX模式(如果尚未进入该模式)”的命令作为XXX模式if-block中的no-op处理。 ,但要对与其他模式关联的if块执行操作。
\ $ \ endgroup \ $
–超级猫
2014年3月11日20:40