恐怖に対処する方法を覚えていますか? あなたは1分間キャッチし、その間あなたはあなたのすべての感情を自由に制御します。 それから、あなたは自分自身に「十分」と言って、問題に真っ向から飛び込みます。 1分が経過しました。
そもそも、どんな動物なのか調べてみましょう。 次のプロパティを強調表示します。
- 攻撃を無視することは不可能です。
- 一箇所に複数のハンドラー。
- ネストされた呼び出しをいくつでも浸透させる。
- プロセッサに渡される独立したデータ構造-hresult、com関数を呼び出すマクロ、および例外メカニズムの不在(または使用したくない)に起因するその他のゴミを思い出してください
そしてそれだけです。 あらゆる種類のパフォーマンスの低下、制御の複雑さはコンテキストに依存し(多くの場合、非常に手に負えない)、それぞれの場合に証明が必要です。
たとえば、ファイルを検索します。
int FindSymbol(TextReader reader, char symb)
{
char cur;
int pos;
while (cur = (char)reader.Read())
{
if (cur == 'a')
throw new FormatException();
pos ++;
if (cur == symb)
return pos;
}
throw new MyException(); }
}
関数を終了するための次のオプションが定義されています。
- 必要なデータが見つかりました(リターンpos)
- ファイルが正しい形式ではありません(スロー)
- ファイルが終了しました(リーダーは例外を発生させます)
機能が機能するための最後のオプションは、最も物議をかもします。 通常、プログラマーは意思決定を実証する上で非常に独創的であり、多くの長所と短所を見つけることができます。非効率、クライアントコードは実装の詳細を知る必要がある、間違った形式はエラーなどです。 これはすべて真実ですが、主なことではありません。 主な長所は十分です。
クライアントは複雑な結果を分析する必要がなくなり、テキストを見つけるように求められました。 そうでなければ、彼もそれを知りません。
別の例:ユーザーの処理はキャンセルボタンをクリックします。 繰り返しますが、このトピックについて長い間議論することができます-このメカニズムは元々作成されたのはなぜですか?
しかし、それが存在し、「キャンセル」ロジックに適している場合、それを使用しないのは愚かなことです。
家で敷居を接着する必要があるとき、私は二度考えることなく、M.Pc-Donaldの本「Wpf ...」を負荷として使用しました。 では、なぜ他の場合に別の方法で行う必要があるのですか?
小さな機能についてどう思いますか? 私は今、他人には単に存在する権利がないと信じています。 この態度では、例外を発生させなければどこにもいないという状況が定期的に発生します。 たとえば、呼び出しスタックの上のループを終了する必要があります。 結局、同じフラグを完了に渡さないでください。 または伝える...
ループが呼び出しスタックの前のレベルではなく、それより高いレベルにある場合は? スローのないすべてのコードは、関数の結果の分析に変わります。 それはとんでもないことになります-他の関数の結果を検証するメソッドを際立たせます。 座って、予期せず「間違った」リファクタリングをロールバックすることを考えます。 しかし、すべてが変わると変更されます。コードは一度に2行または3行削除されます
これが十分に長くなる前に、メソッドとクラスの両方が削除されます)
そして、もう1つの興味深い「フレーバー」-多数の条件演算子です。 アクションを実行する前に分析が開始されると、「これを行うことは可能ですか?」 システムの状態を個別に不明確にするいくつかの操作で構成されるアルゴリズムはそのままにします。 あなたがそれを始めたなら、それをケーキに分けてください、しかし、それを終えてください! 私はそれらについて話していません。 ここでは、必要に応じて、許容可能な解決策を見つけることができます。 そのため、臭いはより多くの条件演算子から発生します。たとえば、操作を実行する前に入力データのセットを分析したり、データ構造の有効性をチェックしたりする場合、または...他に何がわからないのかなどです。 一般に、各データ要素を見て、それが私たちの大きな目標に適しているかどうかを判断し、それらを実装します。 バカじゃない? すぐに計画を実行してみてください。 そして、あなたがしなければならないのは、ごみでコードを乱雑にするためにこのセクションで例外が発生するかもしれないと仮定することです。
例外を提起するこの態度の反対者の間の主な議論は、パフォーマンスの低下です。 これについて議論するのはばかげています-条件ステートメントは数倍効率的です。 ただし、「問題」が1つあります。問題は実際のデータで証明する必要があります。 コードが非常に重要であるとします。 怖い! -リファクタリングに数時間を費やす必要があります。 日、つまり時間ではありません。 ファウラーがデザインに対する彼の態度についてどのように語ったかを思い出してください:「...あるデザインから別のデザインにリファクタリングすることがどれほど難しいかを判断しようとしています。 困難が目に見えない場合、私は選択についてあまり考えずに、最も単純なものに専念します。」
この大胆なアイデアを受け入れると仮定した場合、リファクタリングの順序を決定することは残ります。
- メソッドを、例外を発生させるメソッドの本体と区別します。
- 選択したメソッドのシグネチャに基準を定義します。これは、異なる状況では例外が発生することを示しています。
- 元のメソッドを変更して、基準に応じて例外が発生するようにします。 元のメソッドを「例外のあるメソッド」と呼び、識別されたメソッドを「例外のないメソッド」と呼びます。
- メソッドから拡張メソッドを(コピーして)例外なく作成します。
- 拡張メソッドの本体を、例外のあるメソッド呼び出しに置き換えます。
- 拡張メソッドを使用して例外の配布をブロックし、上昇に応じて、基準をコックするかリセットします。
- 例外なく、メソッドシグネチャを持つメソッドをインターフェイスに追加します。 これらのメソッドの実装では、拡張メソッドを呼び出します。 メソッドが(クラスに関連して)外部インターフェイスの一部でない場合-より良い。 この項目はスキップできます。
- 例外のあるメソッド呼び出しを例外のないメソッドに置き換えます。 インターフェースの実装では、これは必須です(それ以外の場合は開始しないでください)。 コードの置き換えは次のようになります:例外なしのメソッド呼び出し、基準の分析。
- 例外を含むメソッドから拡張メソッドを作成します。 その構造はすでに正しいはずです。 それを労働者にすることだけが残っています。
- 例外のない内線で例外のある残りの呼び出しを置き換えます。
- 例外と例外のないメソッドは、例外なくインターフェースから削除します。 例外の可能性がある拡張。
これは、コードでどのように見えるかです。
- ソースコード:
class SrcClass
{
public void Exec()
{
throw new MyException();
}
}
- 3番目のステップの後:
class SrcClass
{
public void Exec()
{
if (!TryExec())
throw new MyException();
}
public bool TryExec()
{
return false;
}
}
- 9番目のステップの後:
class SrcClass
{
public void Exec()
{
if (!TryExec())
throw new MyException();
}
public bool TryExec()
{
return false;
}
}
static class SrcClassHelper
{
public static bool TryExecHelp(this SrcClass src)
{
try
{
src.Exec();
return true;
}
catch (MyException)
{
return false;
}
}
public static void Exec(this SrcClass src)
{
if (!src.TryExec())
throw new MyException();
}
}
- 完了時に:
class SrcClass
{
public bool TryExec()
{
return false;
}
}
static class SrcClassHelper
{
public static void Exec(this SrcClass src)
{
if (!src.TryExec())
throw new MyException();
}
}
原則として、すべて。 少なくとも例外を提起することへの恐怖を払拭できたことを願っています。そして、今、そのような必要が生じたとき、あなたは解決策を選ぶことにもっと忠実になるでしょう。 そして、おそらく、よりシンプルなものを選択してください。 だから、あなたの受信機はあなたをあまり狂わせずにscるでしょう(私はそれになる可能性があります)。