清理病态嵌套" if {} else {if {} else {if {...}}}"

时间:2016-05-30 18:24:56

标签: c# if-statement nested indentation

我目前不幸在为别人的C#代码工作,这真的让我大吃一惊。我不知道我之前的人是如何维护这段代码的,因为它的各种病态已经破坏了IDE,编译器,运行时环境......

我今天面临的问题涉及一个15兆字节的源文件,它具有真正令人心旷神怡的病态嵌套程度。代码如:

if(var == 0) {
  // do stuff
}
else {
  if(var == 1) {
    // do stuff
  }
  else {
    if(var == 2) {
      // do stuff, identical word for word to the `var == 1` case
    }
    else {
      // etc.
    }
  }
}

在最好的时候,这是一个值得怀疑的风格选择。然而,这与代码的另一种病态结合:其中一些块近千层深。 (我最不愿意测量的最深处超过700.)我真诚地希望我面前的那个人,作为他们最后的行为之一,在被强行分开之前,运行了一个造型工具,导致我面前的憎恶。我无法想象他们可能已经编写了这样的代码,特别是因为代码的每三或四次编辑崩溃了IDE 。 (有时会删除我的源文件副本,作为奖励。)

我写了一个简单的基于正则表达式的工具来尝试压缩更简单的情况,但似乎是半处理然后破坏了这个特定的代码。 (我不确定它是否会失败,因为这段代码也会不时地使用预处理器条件,或者因为最长的匹配长度几乎是10MB而且Lua的正则表达式匹配器不能应对。)我希望有一种广泛使用的工具或技术可以扭转这个问题。我已经不得不使用astyle来清理其他一些风格问题"代码了。 astyle --remove-brackets选项几乎符合我的要求,但要求括号中的语句是单行上的单个语句,这在这里并非如此...(和只是为了穿越我的" t,我检查过; astyle没有造成这个特殊的问题。)

编辑:对问题代码的深入研究揭示了这样的事情:

#if OneThing
int num2296 = otherThing();
#endif
#if AnotherThing
int num44 = otherThing()
int num45 = 0;
#endif
int num72 = 0;
#if OneThing
int num45 = 0; // note: multiple equivalent declarations of num45
#endif
#if OneThing
for(int num2297 = 0; num2297 < num2296; ++num2297) {
  num45 = doSomething(num2297);
#endif
#if AnotherThing
for(int num43 = 0; num43 < num44; ++num43) {
  num45 = doSomething(num43);
#endif
  if(somethingElse(num45)) {
    ++num72;
  }
} // note: only one closing brace for the two protected by #ifs

此代码的两个版本是为不同目的编译的,一个定义了OneThing,另一个定义了AnotherThing。但是,两者之间的大多数差异只是变量名称,逻辑相同。 (大多数,不是全部。)

上述片段末尾的大括号等案例解释了为什么我的简单工具破坏了。这也越来越像设计中的工作保障,而不像无辜的无能。 (如果代码曾经在反编译器生成变量名称num2276的位置,那么它当前

不幸的是,这意味着自动化工具可能不会单独削减它。我只需要轻轻一点,慢慢消除最后一个程序员造成的伤害。我在这里留下这个问题的机会是有一个神奇的工具,我不知道,可以将两个版本转换为SSA并识别和折叠它们的逻辑等价,然后将它们转换回来......

1 个答案:

答案 0 :(得分:6)

您可以使用Roslyn重写代码。将源代码修改为文本并不是一个好方法。使用Roslyn,您可以将其修改为语法树。

也许它可以帮助你压扁一切?

if (a)
 if (b) F2()
 else F3();
else
 F4();

可能成为:

if (a && b) F2();
else if (a && !b) F3();
else F4();

这样,源代码就变成了一个平面列表,在输入分支的条件下更明显。