2016-05-30 8 views
10

私は現在、本当に私の心を吹き飛ばしたSomebody ElseのC#コードで作業している不運があります。さまざまな病理がIDE、コンパイラ、ランタイム環境をクラッシュさせているので、私の前の人がこのコードをどのように維持しているのか分かりません...病理学的にネストされた "if {} else {if {} {} else} {if {...}}}"

私が直面している問題は、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. 
    } 
    } 
} 

これは時代遅れの文句の選択です。しかし、これはコードの別の病理と組み合わされている:これらのブロックのいくつかは深さ約1000レベルであるです。 (私が測定しようとした最も深いのは700歳を超えていました)私の前の人は、このコードから強制的に分離される前の最後の行為の一つとして、私の前に嫌な結果をもたらすスタイリングツールを使いましたことを心から願っています。特にコードの3回目または4回目の編集でIDEがクラッシュするので、今のようにこのコードを書いた可能性があるとは思いません。 (ソースファイルのコピーをボーナスとして削除することがあります)

シンプルなケースを凝縮しようとするシンプルな正規表現ベースのツールを書きましたが、この特定のコードを半分処理して破損しているようです。 (このコードでは時々プリプロセッサの条件文も使用されるため、または一致の最長時間が10MB近くになり、Luaの正規表現マッチャーで対処できないため、失敗するかどうかはわかりません)この問題を逆転させることができる広く使用されているツールまたはテクニックです。私はすでにコードが持っていた他の文章的な "問題"を取り除くためにastyleを使用しなければなりませんでした。 --remove-brackets astyleのオプションほとんど私がしたいことはありますが、括弧で囲まれたステートメントは1行で1つのステートメントにする必要があります。これは大した事例ではありません...(そして私の "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 
このコードの2つのバージョンが異なる目的のためにコンパイルされている

、1 OneThingで。 AnotherThingが定義されています。しかし、2つの違いのほとんどは、ロジックが同一の変数名だけです。 (ほとんどではなくすべて)

上記のスニペットの最後にあるブレースのようなケースが、私の単純なツールが壊れている理由を説明しています。これは、デザインによって雇用保障に似ており、無実の無能感に似ていません。 (コードがnum2276のような変数名は、逆コンパイラによって生成される時点で一度だった場合、それが現在その時点でではありません。)

残念ながら、これは自動化ツールは、おそらくそれをカットしないことを意味します単独で。私はちょうど最後のプログラマーがしたダメージをゆっくりと元に戻すようにスロッグする必要があります。私はSSAに両バージョンを変換し、それらの論理的な等価性を識別して崩壊させ、それらを元に戻し変換することができる奇跡のツールがあります。

+0

スイッチケースは解決策または[責任の連鎖](https://en.m.wikipedia.org/wiki/Chain-of-responsibility_pattern)になります –

+1

'switch'命令がコードにはるかに優れているようですサンプル中に提供される。ところで、良い質問。 –

+1

ブロックをメソッドに抽出することで、より深く深いところに行くことになるでしょう。このビデオは、私が[実用的なリファクタリング](https://youtu.be/aWiwDdx_rdo?t=3235)(自分のビデオではない)を意味するアイデアを提供します。私は関連するタイムスタンプにリンクしましたが、ビデオ全体を見る価値があります。それはいくつかの非常に恐ろしいコードをリファクタリングのウォークスルーを与えるが、あなたはそれを打つかもしれない。 – Tone

答えて

6

Roslynを使用して書き直すことができますコード。ソースコードをテキストとして変更するのは良い方法ではありません。 Roslynを使用すると、構文ツリーとして変更できます。

多分、すべてを平坦化するのに役立ちますか?

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

はなれる:

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

その方法は、ソースコードは、フラットなリストとなり、分岐が入力されているどのような条件の下でより明らかです。

+0

Roslynは、私が望んでいることに理想的に見えます。私はまだC#に慣れていないので、最初にいくつかのアプローチを試していきますが、そのようなツールがあることを知っているのはとても良いことです。 (もし他のものがなければ、私が最後に行ったソースファイルを取得するときには有益であると確かに証明されるでしょう... 25MB以上のクロックで動作しますが、少なくとも15MBはタブ文字です)O_O) –

+0

Resharperは、複数のメソッドをインライン化して復讐を実現する方法としてインラインで機能します。コードサイズは指数関数的に増加します。 – usr

+0

このコードをもっと見るほど、悪意のあるものはすべて見えます。私はOPを編集してクレイジーの別の層を実証しました。これはRoslynを使って自動的にダメージを取り消すように見えるでしょう。 –