2012-03-23 24 views
16

はDelphiのExit声明について読んで(例えばhereを参照してください)、私はそれについて書くことは、すべての著者が、たとえば、アドバイス断片を与える義務を感じていることを無視することはできません。DelphiのExit文は危険ですか?

警告:注意して使用 - ジャンプがあります構造化されたコーディングとは異なる概念です。コードのメンテナンスが難しくなります。今

は、私は、UnixでのCおよびC++から来ていると私はリエントラントの問題に精通しているんだけど、それがあるべきその自然の最後に到達する前に、正直なところ、私はDelphiでの関数から戻った理由を把握することはできません悪の。

デルファイのすべての関数とプロシージャが再入可能とみなされない限り、

私には何が欠けていますか?

+0

この質問は、議論と推測を求めるので、ここでは本当に適切ではありません。より適切な場所ではなく、[プログラマー](http://programmers.stackexchange.com)に属しています。 [FAQ](http://stackoverflow.com/faq)は、このタイプの質問を、このサイトの形式とデザインにはあまり適していないと具体的に言及しています。プログラマーに移行する投票。 –

+0

私はあなたに次の記事を勧めますhttp://programmers.stackexchange.com/questions/77530/best-practices-concerning-exit-in-delphiこれは、詳細な方法で同じ件名をカバーしています。 – RBA

+1

リンクされたサイトは、誤解と品質の低い情報でよく知られています。それを無視します。彼がうまくいっていないのは、*単一出口点*の概念です。 – OnTheFly

答えて

11

考え方は2つあります。

1つの考え方では、関数には単一の終了点が必要です。多くの多くのコーディング標準で原則としてそれが強制されています。これの動機は、スパゲッティコードをgotos、複数の出口などの大きな機能でいっぱいに維持するという難しい経験から来ています。

スパゲッティコードは悪いと言われていますが、実際的なものであり、ドグマティックルールに従うのではなく、メリットのコーディングスタイルを判断する必要があります。たとえば、多くのプログラマーは、exitの使用を控えたときに、深くインデントされた機能よりもガード句がはるかに優れていると感じています。例として、Martin Fowlerの優れたリファクタリングカタログの次の例を考えてみましょう:Replace Nested Conditional with Guard Clauses

基本的にすべてが個人の好みになります。私は個人的にガード条項の使用を奨励しますが、長い手順では野生の退出を控えるようにします。

+3

+1。あなたが明白なことを言っていると思いますが、あなたはそれをかなりうまく表現しました! –

+0

正しく使用すると、Exitに何も悪いことはありません。私は適切なときにそれを使います。他のすべてのツールと同じように、それはツールです。 IF-ELSE上のいくつかの条件を確認しながら、手順の初めに明確な終了を好む – Runner

9

「これを使用しない」または「終了は悪い」とは言わないことがありません。 「慎重に使用してください」と言います。そして、メンテナンスが難しくなると言います。あなたが大規模なメソッドを持っていると途中でこのどこかのような行があります場合たとえば、あなたは完全にそれを逃すかもしれない:

if aLocalObject.CheckSomeValue(aParameter) <> RIGHT_VALUE then Exit; 

をそして、ええ、私は実際には、残念ながら、前にそのようなものを見てきました。 :(

多くの問題は、親指のいくつかのルールを緩和することができる。

  • は、必ず自分のライン上のExit(およびBreakContinue)文を置くことが欠場する彼らが難しくなります
  • 大規模なものより小さな方法を好んで、合理的であれば大きな方法を小さなものに分割します(これは絶対的なルールではありません) "すべてをできるだけ単純にしますが、単純にはしません。")
  • try/finallyブロックを使用して、手順の外に漏れや破損を起こすことなく安全に行うことができます。
+1

OK、* *なぜ* [upvotesを取得していない!](http://stackoverflow.com/questions/) 9841515/list-all-web-browsers-on-a-machine):) –

+2

@アンドレアス:ガー!私の目! –

0

多くの場合と同様に、exitはいくつかの場合に有用であり、他のものでは役に立ちません。いくつかのコンテナを検索し、コンテナのオブジェクトをループ内の '結果'にロードし、一致するプロパティを探している小さな関数では、非常に貴重です。見つかった場合、関数はただ終了することができます。そうでない場合は、ループの後、 '通常の'戻りの直前に結果をnilに設定できます。また

、きっと私だけ上げのポイントに同意することができます

...デバッグながら、それが実行を停止する手順の上部にある[終了]に押し込まれていない、いくつかの開発者が存在することができます他のポスターから。大規模で複雑な手続きに埋もれた出口

2

David'sとMasonの素晴らしい回答に加えて、Exitが好きな使い方を分かちたいと思います。それを「セーフガード」、「最後のリゾートの提供者」とは全く反対にしましょう。 ;)

基本的な考え方:

function Search(List: TList; Item: TObject): Integer; 
begin 
    for Result := 0 to List.Count - 1 do 
    if List[Result] = Item then 
     Exit; 
    Result := -1; 
end; 

他のより現実的な例(this answerthis answerから):Delphiのヘルプからの引用で

const 
    Order: array[0..6] of String = ('B', 'C', 'A', 'D', 'G', 'F', 'E'); 

function GetStringOrder(const S: String; CaseSensitive: Boolean): Integer; 
begin 
    for Result := 0 to Length(Order) - 1 do 
    if (CaseSensitive and (CompareStr(Order[Result], S) = 0)) or 
     (not CaseSensitive and (CompareText(Order[Result], S) = 0)) then 
     Exit; 
    Result := Length(Order); 
end; 

function FindControlAtPos(Window: TWinControl; const ScreenPos: TPoint): TControl; 
var 
    I: Integer; 
    C: TControl; 
begin 
    for I := Window.ControlCount - 1 downto 0 do 
    begin 
    C := Window.Controls[I]; 
    if C.Visible and PtInRect(C.ClientRect, C.ScreenToClient(ScreenPos)) then 
    begin 
     if C is TWinControl then 
     Result := FindControlAtPos(TWinControl(C), ScreenPos) 
     else 
     Result := C; 
     Exit; 
    end; 
    end; 
    Result := Window; 
end; 

と結論コンパイラのエラーメッセージFOR-Loop vaループはgoto文または終了文で残っている場合にのみ、ループの制御変数の最終値に依存することができます

:riable「> <要素」がループ後不定になることがあります。

+1

線形検索の例は、この使用法の標準的な例です+1 –

関連する問題