18

最近 ReSharper をif使用していると、条件を反転してcontinueステートメントを使用することで、特定の場所でのネストを減らすことが提案されています。

ネストされた条件:

foreach(....)
{
    if(SomeCondition)
    {
        //do some things

        if(SomeOtherNestedCondition)
        {
            //do some further things
        }
    }
}

ステートメントを続ける:

foreach(....)
{
    if(!SomeCondition) continue;

    //do some things

    if(!SomeOtherNestedCondition) continue;

    //do some further things
}

パフォーマンスとメモリの問題のために入れ子を減らしたい理由と、2 つのスニペットがどのように対応するかについてのロジックの一部は理解していますが、私の開発経験から、コードを読むときは前の例の方が簡単に理解できます。

どちらのアプローチを好みますか、またその理由は何ですか? continue日常のコードで入れ子になった ifを使用していますか?

4

10 に答える 10

31

原則として、複雑さを軽減するため、除外する条件で常にステートメントブロックを開始するのが最善であることがわかりましたが、さらに重要なことは、コードとメモリのパフォーマンスを向上させることができる、それ以上ステップアップする前に互換性のない状況をスローすることです。これにより、メンテナンス期間中の条件の安全性も確保され、無効なシナリオが属していないコードに渡される可能性が低くなります。

さらに、スコープレイヤーが利用可能なものを混乱させないため、個人的には2番目の方が読みやすいと思います。後であるレイヤーで変数を作成し、別のレイヤーで使用できないことに気付かなかったり、それらを適切に変更するなどの管理を行います。

これは単なるループの継続ではなく、メソッドの条件が返されることも意味します。メソッドを開始する代わりに

if (valid)
{
    do stuff;
}

常に開始する必要があります

if (notValid)
{
    return;
}
于 2010-07-26T19:18:06.530 に答える
8

重要なパフォーマンスの違いはありません。これはすべて読みやすさに関するものです。個人的には後者の方が読みやすいと思います。ネスティングが少なくなり、読みやすくなります。

于 2010-07-26T19:16:16.173 に答える
6

簡潔な答え:

私はインデントを使用する傾向があり、実際の決定ロジックが行われることを意味します。複数の可能な実行パスが予想されるロジック。

より長い答え:

私は通常、先行する「改行」ステートメント ( 、、、または)よりもインデントされたブロックを好みます。continuebreakreturnthrow

理由:私の意見では、ステートメントを壊すと、一般的にコードが読みにくくなります。コードをインデントすると、決定ロジックが発生する場所を簡単に見つけることができます。それは、インデントが少ないコードの最初の行になります。代わりに、条件を反転したブレーク ステートメントを使用する場合は、コードがどのように分岐するか、および特定のコードがスキップされる状況を理解するために、より多くの作業を行う必要があります。

私にとって注目すべき例外が 1 つあります。それは、メソッドの先頭で引数を検証することです。このコードを次のようにフォーマットします。

if (thisArgument == null) throw new NullArgumentException("thisArgument");
if (thatArgument < 0) throw new ArgumentOutOfRangeException("thatArgument");
...

理由:これらの例外が実際にスローされるとは思わないため (つまり、メソッドが正しく呼び出されることを期待しています。呼び出し関数は無効な入力を検出する責任があります (IMO))、残りのすべてをインデントしたくありません。起こるべきではないことのコードの。

于 2010-07-26T19:38:20.937 に答える
4

スタイルcontinueコード付き; SomeOtherNestedCondition に依存しない 3 番目の操作をどのように処理しますか。これにより、コードの順序が重要になり、IMO によって保守性が低下します。

例えば:

foreach(....) 
{ 
    if(!SomeCondition) continue; 

    //do some things 

    if(!SomeOtherNestedCondition) continue; 

    //do some further things 

    if(!SomeSecondNonNestedCondition) continue;

    // do more stuff
}

SomeOtherNestedCondition が原因でcontinue;が発生したが、SomeSecondNonNestedCondition が引き続き実行される場合はどうなりますか?

「コード」の各ビットをリファクタリングし、ネストされたif()s を使用してリファクタリングされた各メソッドを呼び出し、ネストされた構造を維持します。

于 2010-07-26T19:18:02.483 に答える
2

簡単な答え。どちらが読みやすく、理解しやすいか。

于 2010-07-26T19:16:24.140 に答える
2

2 つを組み合わせて使用​​します。if(condition) continue;ループの先頭でandを使用if(condition) return;して現在の状態を検証し、ネストされたifステートメントをさらに下に使用して、達成しようとしているもののフローを制御します。

于 2010-07-26T19:33:57.860 に答える
1

メモリやパフォーマンスに違いはありません。基礎となる IL は分岐/ジャンプ命令の選択にすぎないため、ループの先頭に戻るか「else」ステートメントに戻るかは問題ではありません。

どちらか読みやすいほうを選ぶべきです。私は個人的に「継続」を避けることを好みますが、ネストのレベルが多い場合は、2 番目の例の方が簡単に実行できます。

于 2010-07-26T19:18:36.763 に答える
1

s を使用continueすると、通常の手続き型コードのレベルでコードの大部分が作成されます。それ以外の場合、チェックが 5 つある場合は、インデント サイズに応じて、メソッドの「肉」を 10 文字または 20 文字インデントします。これらは 10/20 文字であり、長い行を表示するにはスクロールする必要があります。

于 2010-07-26T19:19:09.617 に答える
0

ただし、私の開発経験からすると、コードを読むときは前の例の方が簡単に理解できます。

まあ、それはあなたの個人的な意見だと思います。たとえば、私は、コードが読みにくくなるため、そのようなネストを避けるようにしています。

「後」バージョンよりも「前」バージョンの方が好きな場合は、それを使用してください。
ReSharper を構成するだけで、本当にやりたいことを提案してくれます。

常に心に留めておいてください: ReSharper は非常に「ばかげた」リファクタリング ツールです。開発者を置き換えることはできません。他の方法では愚かなコピー&ペースト作業を行うことによってのみ、彼を助けることができます.
ReSharper によって行われた一部のリファクタリングは、ReSharper が反対のリファクタリングを提案する状況でも結果をもたらします。

したがって、ReSharper の提案をベスト プラクティスとしてではなく、実行できる可能性として見てください。

ところで: ここでは、パフォーマンスに関する考慮事項によって駆動される必要があります。パフォーマンスに本当に顕著な違いがあるとしたら、私は驚かれることでしょう。

于 2010-07-26T19:18:33.060 に答える