パラメータに基づいて例外をスローする/しないでください-なぜこれは良い考えではないのですか?

StackOverflow https://stackoverflow.com/questions/624647

質問

MSDNを掘り下げていたところ、この記事興味深いアドバイスが1つありました。オプションに基づいて例外をスローする、またはスローしないパブリックメンバーを持たないでください。

例:

Uri ParseUri(string uriValue, bool throwOnError)

もちろん、今では99%のケースでこれは恐ろしいことですが、その時々の使用は正当化されますか?

使用した例の1つは、「AllowEmpty」を使用した場合です。データベースまたは構成ファイルのデータにアクセスするときのパラメーター。例:

object LoadConfigSetting(string key, bool allowEmpty);

この場合、代替手段はnullを返すことです。ただし、呼び出し元のコードにはnull参照チェックが散らばっています。 (また、この方法では、特に設定する必要がある場合は、nullを具体的に構成可能な値として実際に許可することもできません。)

あなたの考えは何ですか?なぜこれが大きな問題になるのですか?

役に立ちましたか?

解決

ブール値に基づいてスロー/ノースローの決定を行うことは間違いなく悪い考えだと思います。つまり、コードの一部を見ている開発者は、ブール値の意味を判断するためにAPIの機能知識を持っている必要があります。これ自体は悪いことですが、基礎となるエラー処理を変更すると、開発者がコードを読んでいる間に間違いを犯しやすくなります。

この場合、2つのAPIを持つ方がはるかに優れており、読みやすくなります。

Uri ParseUriOrThrow(string value);

bool TryParseUri(string value, out Uri uri);

この場合、これらのAPIの機能は100%明確です。

パラメーターとしてブール値が悪い理由に関する記事: http ://blogs.msdn.com/jaredpar/archive/2007/01/23/boolean-parameters.aspx

他のヒント

通常、1つのエラー処理メカニズムを選択し、それを一貫して使用するのが最善です。この種のフリップフロップコードを許可しても、開発者の生活を実際に改善することはできません。

上記の例では、解析が失敗してthrowOnErrorがfalseの場合はどうなりますか?ユーザーは、返される場合はNULLかどうかを推測する必要があります。

確かに、より優れたエラー処理方法として、例外と戻り値の間で継続的な議論がありますが、一貫性を保ち、選択に固執することについてはコンセンサスがあると確信しています。 APIはユーザーを驚かせることができず、エラー処理はインターフェイスの一部であり、インターフェイスと同じように明確に定義する必要があります。

読みやすさの観点から見ると、ちょっと厄介です。開発者は、すべてのメソッドが例外をスローすることを期待する傾向があり、例外を無視したい場合は自分でキャッチします。 'boolean flag'アプローチでは、すべてのメソッドがこの例外を禁止するセマンティクスを実装する必要があります。

ただし、MSDNの記事では厳密に「throwOnError」フラグについて言及していると思います。これらの場合、メソッド自体の内部でエラーが無視されるか(非表示であるため不良)、ある種のnull /エラーオブジェクトが返されます(エラー、一貫性のないエラーを処理するために例外を使用していないため不良です) -prone)。

あなたの例は私には問題ないようですが。例外は、メソッドがその義務を実行できないことを示します。戻り値はありません。ただし、 'allowEmpty'フラグはメソッドのセマンティクスを変更します-したがって、例外( 'Empty value')であったはずの内容が予期され、有効になりました。さらに、例外をスローした場合は、構成データを簡単に返すことはできません。したがって、この場合は問題ないようです。

どのパブリックAPIでも、エラーが発生した場合に何が起こるかが明らかではなくなるため、障害のある状態をチェックする2つの方法を持つことは本当に悪い考えです。コードを見るだけでは役に立ちません。 flagパラメーターのセマンティクスを理解する必要があります(そして、それが式であることを妨げるものは何もありません)。

nullのチェックがオプションではなく、この特定の障害から回復する必要がある場合、後でキャッチして適切に処理できるように、特定の例外を作成することを好みます。それ以外の場合は、一般的な例外をスローします。

これに沿った別の例は、いくつかの値型のTryParseメソッドのセットです

bool DateTime.TryParse(文字列テキスト、DateTime)

donTThrowExceptionパラメーターを使用すると、例外のポイント(すべての言語)が無効になります。呼び出し元のコードが必要な場合:

public static void Main()
{
        FileStream myFile = File.Open("NonExistent.txt", FileMode.Open, FileAccess.Read);
}

彼らは大歓迎です(C#にはチェック例外もありません)。 Javaでも同じことが達成されます。

public static void main(String[] args) throws FileNotFoundException
{
        FileInputStream fs = new FileInputStream("NonExistent.txt");
}

どちらの方法でも、呼び出し先ではなく例外を処理する(または処理しない)方法を決定するのは呼び出し元の仕事です。

リンク先の記事には、制御フローに例外を使用すべきではないという注意があります-これは、質問の例で暗示されているようです。例外は、メソッドレベルの失敗を反映する必要があります。エラーをスローしても大丈夫という署名を持つことは、デザインが考え抜かれていないように思えます。

Jeffrey RichtersはC#を介してCLRを指摘しています-「メソッドが名前で示されているようにタスクを完了できない場合、例外をスローする必要があります」。

彼の本も非常に一般的なエラーを指摘しています。人々はすべてをキャッチするコードを書く傾向があります(彼の言葉"例外の適切な使用について適切に訓練されていない開発者の遍在する間違いは、キャッチブロックをあまりにも頻繁に、不適切に使用する傾向があります。例外をキャッチすると、この例外を予期していたこと、それが発生した理由を理解し、対処方法を知っていること。")

そのため、期待できる例外をコーディングしようとしています。そうしないとエラーになります。

引数を検証して例外を防止し、処理できるものだけをキャッチします。

エラーが例外を引き起こすか、単にエラー表示を返すかを示すパラメーターがあると便利な場合があります。そのようなパラメーターは外部ルーチンから内部ルーチンに簡単に渡すことができるからです。次のようなものを検討してください:

  Byte [] ReadPacket(bool DontThrowIfNone)//存在しない場合はnullを返すものとして文書化   {     int len = ReadByte(DontThrowIfNone); //何もなければ-1を返すように文書化     if(len

データの読み取り中にTimeoutExceptionなどの例外が発生する場合、そのような例外はReadByte()またはReadMultiBytesbytes()内でスローされる必要があります。ただし、このようなデータの欠如が正常であると見なされる場合、ReadByte()またはReadMultiBytesbytes()ルーチンは例外をスローしません。単純にdo / tryパターンを使用する場合、ReadPacketルーチンとTryReadPacketルーチンはほぼ同一のコードである必要がありますが、1つはRead *メソッドを使用し、もう1つはTryRead *メソッドを使用します。イッキー。

ブール値よりも列挙型を使用した方がよい場合があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top