98

次のコードを想像してみてください。

void DoThis()
{
    if (!isValid) return;

    DoThat();
}

void DoThat() {
    Console.WriteLine("DoThat()");
}

voidメソッド内でreturnを使用しても大丈夫ですか?パフォーマンスの低下はありますか?または、次のようなコードを作成することをお勧めします。

void DoThis()
{
    if (isValid)
    {
        DoThat();
    }
}
4

11 に答える 11

183

voidメソッドでの戻りは悪くありませんが、ネストを減らすためにステートメントを反転ifするのが一般的な方法です。

また、メソッドのネストを減らすことで、コードの可読性と保守性が向上します。

実際、returnステートメントのないvoidメソッドがある場合、コンパイラーは常にその最後にret命令を生成します。

于 2009-08-16T02:11:51.237 に答える
33

(ネストされたコードとは対照的に) ガードを使用するもう 1 つの大きな理由があります。別のプログラマーが関数にコードを追加する場合、それらはより安全な環境で動作します。

検討:

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }
}

対:

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
}

ここで、別のプログラマーが obj.DoSomethingElse(); という行を追加したとします。

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }

    obj.DoSomethingElse();
}

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
    obj.DoSomethingElse();
}

明らかにこれは単純なケースですが、プログラマーは最初の (ネストされたコード) インスタンスでプログラムにクラッシュを追加しました。2 番目の例 (ガードを使用した早期終了) では、ガードを通過すると、コードは意図しない null 参照の使用から保護されます。

確かに、優れたプログラマーはこのような間違いを (しばしば) しません。しかし、予防は治療よりも優れています。この潜在的なエラーの原因を完全に排除する方法でコードを書くことができます。ネスティングは複雑さを増すため、ベスト プラクティスではコードをリファクタリングしてネスティングを減らすことをお勧めします。

于 2009-08-16T06:52:22.263 に答える
19

悪い習慣??? とんでもない。実際、検証が失敗した場合は、できるだけ早くメソッドから戻って検証を処理することをお勧めします。そうしないと、大量のネストされた if と else が発生します。早期に終了すると、コードの可読性が向上します。

同様の質問に対する回答も確認してください: if-else の代わりに return/continue ステートメントを使用する必要がありますか?

于 2009-08-16T03:36:12.470 に答える
8

最初の例は、guard ステートメントを使用しています。ウィキペディアから:

コンピューター プログラミングでは、ガードはブール式であり、プログラムの実行が問題の分岐で続行される場合に true と評価される必要があります。

メソッドの先頭に一連のガードを配置することは、完全に理解できるプログラミング方法だと思います。基本的に「これらのいずれかが真の場合、このメソッドを実行しないでください」と言っています。

したがって、一般的には次のようになります。

void DoThis()
{
  if (guard1) return;
  if (guard2) return;
  ...
  if (guardN) return;

  DoThat();
}

それならもっと読みやすいと思います:

void DoThis()
{
  if (guard1 && guard2 && guard3)
  {
    DoThat();
  }
}
于 2009-08-16T06:07:22.107 に答える
8

それは悪い習慣ではありません (すでに述べたすべての理由から)。ただし、メソッドに含まれる戻り値が多いほど、より小さな論理メソッドに分割する必要がある可能性が高くなります。

于 2009-08-16T04:35:56.727 に答える
3

パフォーマンスの低下はありませんが、2番目のコードは読みやすく、保守が容易です。

于 2009-08-16T02:08:43.273 に答える
2

この場合、2 番目の例の方が優れたコードですが、それは void 関数から戻ることとは関係ありません。単純に 2 番目のコードがより直接的だからです。しかし、void 関数から戻ることはまったく問題ありません。

于 2009-08-16T04:22:40.580 に答える
0

それは完全に大丈夫で、「パフォーマンスの低下」はありませんが、角かっこなしで「if」ステートメントを書くことは決してありません。

いつも

if( foo ){
    return;
}

ずっと読みやすくなっています。また、コードの一部がステートメント内に含まれていないのに、含まれていないと誤って想定することはありません。

于 2009-08-16T02:16:00.277 に答える
0

これについては、若いウィッパースナッパーの皆さんとは意見が一致しません。

メソッドの途中で return を使用することは、void であろうとなかろうと、非常に悪い習慣です。その理由は、ほぼ 40 年前に故 Edsger W. Dijkstra によって、よく知られている「GOTO ステートメントは有害であると見なされる"、および Dahl、Dijkstra、および Hoare による "Structured Programming" に続きます。

基本的な規則は、すべての制御構造とすべてのモジュールが、厳密に 1 つの入口と 1 つの出口を持つべきであるということです。モジュールの途中での明示的な return はそのルールを破り、プログラムの状態について推論することをはるかに難しくし、その結果、プログラムが正しいかどうかを判断することがはるかに難しくなります (これははるかに強力なプロパティです)。 「機能するように見えるかどうか」よりも)。

「有害と見なされる GOTO ステートメント」と「構造化プログラミング」は、1970 年代の「構造化プログラミング」革命を開始しました。これらの 2 つの要素が、現在、if-then-else、while-do、およびその他の明示的な制御構文が存在する理由であり、高級言語の GOTO ステートメントが絶滅危惧種のリストに含まれている理由です。(私の個人的な意見では、絶滅種のリストに載せる必要があります。)

Message Flow Modulator は、最初の試行で承認テストに合格し、逸脱、放棄、または「ええ、しかし」言葉遣いもなく、これまでにない最初の軍事用ソフトウェアであることに注意する価値があります。 GOTO ステートメント。

また、Nicklaus Wirth が、Oberon プログラミング言語の最新バージョンである Oberon-07 の RETURN ステートメントのセマンティクスを変更し、型付きプロシージャ (つまり、関数) の宣言の末尾部分に変更したことにも言及する価値があります。関数本体の実行文。変更についての彼の説明は、以前の形式が構造化プログラミングの 1 つの出口の原則に違反していたという理由だけでそれを行ったと述べています。

于 2009-08-16T05:55:45.130 に答える
-3

オブジェクトが null の場合など、何も返さない代わりに例外をスローします。

メソッドはオブジェクトが null ではないことを期待しており、そうではないため、例外をスローして呼び出し元に処理させる必要があります。

しかし、それ以外の場合は、早期復帰は悪い習慣ではありません。

于 2016-10-25T13:23:48.227 に答える