2016-05-30 17 views
10

Ich habe derzeit das Pech, an Somebody Elses C# -Code zu arbeiten, was mich wirklich umgehauen hat. Ich habe keine Ahnung, wie die Person vor mir diesen Code jemals gepflegt hat, da ihre verschiedenen Pathologien die IDE, den Compiler, die Laufzeitumgebung abgestürzt sind ...Aufräumen pathologisch verschachtelt "if {} else {if {} else {if {...}}}"

Das Problem, mit dem ich heute konfrontiert bin, beinhaltet eine 15-Megabyte-Quelldatei weist einen wahrhaft unglaublichen Grad an pathologischer Verschachtelung auf. Code wie:

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. 
    } 
    } 
} 

Dies ist eine fragwürdige Stilwahl zu den besten Zeiten. Dies verbindet sich jedoch mit einer anderen Pathologie des Codes: einige dieser Blöcke sind fast tausend Ebenen tief. (Das tiefste, was ich zu messen versuchte, war weit über 700.) Ich hoffe aufrichtig, dass die Person vor mir, als eine ihrer letzten Handlungen, bevor sie gewaltsam von diesem Kodex getrennt wurde, ein Styling-Tool führte, das zu dem Gräuel vor mir führte. Ich kann mir nicht vorstellen, dass sie diesen Code möglicherweise so geschrieben haben könnten, wie er jetzt ist, zumal jede dritte oder vierte Bearbeitung des Codes die IDE stürzt. (Und manchmal löscht meine Kopie der Quelldatei, als Bonus.)

Ich schrieb ein einfaches Regex-basiertes Tool, um zu versuchen, die einfacheren Fälle zu verdichten, aber es scheint zu halbieren und dann diesen bestimmten Code zu verfälschen. (Ich bin nicht sicher, ob es scheitert, weil dieser Code von Zeit zu Zeit auch Präprozessor-Bedingungen verwendet, oder weil das längste der Matches fast 10 MB lang ist und Lua's regulärer Ausdruck-Matcher einfach nicht zurechtkommt.) Ich hoffe, dass es da ist ein weit verbreitetes Werkzeug oder eine Technik, die dieses Problem umkehren kann. Ich musste bereits Astyle verwenden, um einige andere stilistische "Probleme", die der Code hatte, aufzuräumen. Die --remove-brackets Option für astyle fast macht, was ich will, aber erfordert, dass die geklammerte Anweisung eine einzelne Aussage in einer einzigen Zeile sein, die hier sehr nicht der Fall ist ... (Und nur um meine "t" s zu überqueren, ich überprüfte, astyle nicht dieses besondere Problem erstellen)

Edit: Deeper Untersuchung des Problems Code zeigt Dinge wie diese:

#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 

Zwei Versionen dieses Codes werden für verschiedene Zwecke zusammengestellt, eines mit OneThing. definiert und eins mit AnotherThing definiert. Die meisten Unterschiede zwischen den beiden sind jedoch nur Variablennamen, die logisch identisch sind. (Most, not all.)

Fälle wie die Klammer am Ende des obigen Schnipsel erklärt, warum mein einfaches Werkzeug brach. Das sieht auch mehr und mehr nach Arbeitsplatzsicherheit aus und weniger nach unschuldiger Inkompetenz. (Wenn der Code einmal an einem Punkt war, wo ein Variablenname wie num2276 würde durch einen Decompiler erzeugt wird, ist es nicht derzeit an diesem Punkt.)

Leider bedeutet dies ein automatisiertes Tool wird wahrscheinlich nicht schneiden allein. Ich muss nur noch durchgehen und langsam den Schaden beseitigen, den der letzte Programmierer angerichtet hat. Ich überlasse diese Frage hier auf die Chance, es gibt ein wunderbares Werkzeug, das, ich weiß nicht, kann beide Versionen in SSA konvertieren und ihre logischen Äquivalenzen identifizieren und reduzieren und dann zurück konvertieren ...

+0

Switch-Fall kann eine Lösung oder [Kette der Verantwortung] sein (https://en.m.wikipedia.org/wiki/Chain-of-responsibility_pattern) –

+1

Scheint eine 'switch' Anweisung wird viel viel besser für den Code sein in der Probe zur Verfügung gestellt. Übrigens: gute Frage. –

+1

Ich würde wahrscheinlich nähern, indem Sie Blöcke zu Methoden, tiefer und tiefer zu extrahieren. Dieses Video gibt eine Vorstellung davon, was ich mit [Praktisches Refactoring] meine (https://youtu.be/aWiwDdx_rdo?t=3235) (nicht mein Video). Ich habe mich mit einem relevanten Zeitstempel verbunden, aber es lohnt sich, das ganze Video anzuschauen. Es gibt einen Rundgang durch Refactoring einiger ziemlich horrenden Code, aber Ihre könnte es einfach schlagen. – Tone

Antwort

6

Sie könnten Roslyn umschreiben der Code. Es ist kein guter Ansatz, Quellcode als Text zu ändern. Mit Roslyn können Sie es als Syntaxbaum modifizieren.

Vielleicht hilft es Ihnen, alles zu glätten?

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

Könnte werden:

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

Auf diese Weise der Quellcode wird eine flache Liste und es ist noch deutlicher, unter welchen Bedingungen ein Zweig eingegeben wird.

+0

Roslyn sieht ideal aus für das, was ich mir erhoffe. Da ich mit C# noch nicht sehr vertraut bin, werde ich zuerst ein paar andere Ansätze ausprobieren, aber es ist sehr gut zu wissen, dass es ein Werkzeug gibt, auf das man zurückgreifen kann. (Wenn es nichts anderes ist, wird es sicherlich nützlich sein, wenn ich zu der letzten Quelldatei komme, die ich verschoben habe ... mit mehr als 25 MB, wovon mindestens 15 MB Tabulatorzeichen sind. O_O) –

+0

Vielleicht hat der Typ das benutzt Resharper-Feature "Inline", um viele Methoden zu integrieren, um Rache zu üben. Die Code-Größe kann exponentiell ansteigen, wenn Sie das tun. – usr

+0

Je mehr ich diesen Code betrachte, desto bösartiger scheint das Ganze. Ich habe das OP bearbeitet, um eine weitere Ebene des Verrückten zu demonstrieren, die den Einsatz von Roslyn zu verhindern scheint, um den Schaden automatisch rückgängig zu machen. –