(xyz == null)チェックが「保護的」ではないことをどのように説明しますか
-
22-07-2019 - |
質問
iにIf nullチェックを常に配置する開発者が数人いる
例:
Run(Order order)
{
if (order == null) return;
}
誰かがnullのパラメータを渡した場合、クラスを保護していると考えているため、コード内で私は彼らに彼らのロジックの欠陥を伝えようとしています消費者を遠ざけます。
別の提案は、高速で失敗して例外をスローする前提条件またはガードクラスを持つことです。消費者が他の問題を抱えている可能性があるという事実を無視して、それをマスクするのに役立ちます。
どのようにすれば、あなたのクラスがそれほど寛容であってはならないという事実を人々に理解させることができますか。誰かが良いデータを渡さなかった場合、彼らに伝えられるべきです。
この点を理解するのに役立つ良い記事や提案はありますか?
解決
クラスが null
引数を受け入れられない場合、最善の方法は次のとおりです:
if (arg == null)
throw new ArgumentNullException();
これは、スタックの深部で NullPointerException
を取得するよりも非常に望ましい方法です。最悪の場合のシナリオでは、その null
をどこかにキャッシュし、かなり後でまで実際に例外をトリガーせず、問題をデバッグする楽しさを確認します then 。
そして他の人が述べたように、契約は時々 null
は大丈夫だと言っています。その場合、コードの一部をガード句で囲むのは正しいことですが、それでも最適な設計は、オプションのnull引数なしでオーバーロードを追加することだと思います。
他のヒント
それは本当に正確な状況に依存します。あなたが示しているように、「コードにnullチェックを入れないでください」のような一般的な提案をすることはめったに勧められません。クラスの契約は、合法的なものとそうでないものを定義する必要があります。しかし、nullを渡すことが受け入れられないことを契約で明確にしている場合、例外は実際に適切な応答です。
他の皆が言ったように、関数は予期されたときに何もしなかったため、本番環境で不可解な問題を起こすよりも早く失敗することが非常に望ましいです。あなたの例のように、関数がnull引数を返す場合)
関数が返らず、単に NullReferenceException
をスローする場合でも、引数がnullであることがわかっている場合、バグを解決するのは簡単です。関数が NullReferenceException
をスローする場合、 null
が何であるか、または誰の障害であるかはわかりません。
ArgumentNullException
が何らかの理由でパラメータを取ることを追加したい。
書く方が良い
if(myArg == null) throw new ArgumentNullException("myArg");
paramName
なしで ArgumentNullException
をスローするよりも。
これにより、5つのパラメーターを受け取る関数から例外がある場合、どのパラメーターが問題を引き起こしたかがわかります。これは、デバッガを接続できない場合に特に重要です。 (たとえば、実稼働Webサーバーまたはエンドユーザーマシン上)
多くの関数を記述している場合、特に文字列用のIntelliSenseがないため、これは大きなオーバーヘッドになる可能性があります。これらのチェックを生成するコードスニペットを作成しました:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Check for null arguments</Title>
<Shortcut>tna</Shortcut>
<Description>Code snippet for throw new ArgumentNullException</Description>
<Author>SLaks</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
<SnippetType>SurroundsWith</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>Parameter</ID>
<ToolTip>Paremeter to check for null</ToolTip>
<Default>value</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[if ($Parameter$ == null) throw new ArgumentNullException("$Parameter<*>quot;);
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
.net 4.0のコードコントラクトにより、この動作の一貫性が向上することが期待されます。 コードコントラクトについて説明している記事は、アイデアを広めるのに役立ち、将来、この種の構文がメソッドを提供します。
まだ見ていませんが、 eiffel.comには2つのプレゼンテーションがあります(スライド+オーディオ)契約による設計のトピック。これらの人たちはコンセプトを発明しました。
このような練習が間違っている理由を人々に伝えることができない場合があります-彼らは自分でそれを把握する必要があります。しかし、この問題が原因で何らかの厄介な障害を引き起こすユニットテストを考え出し、エラーをデバッグすることで、彼らがそこに到達するのを助けることができます。
メソッドのコントラクトで引数がnullであってはならないと指定されている場合、正しいことは、次のようにAssertを使用して明示的にすることです:
Debug.Assert( item != null, "Null items are not supported );
これは、デバッグ構成を使用して実行可能ファイルをビルドすると高速に失敗しますが、リリース構成を使用してビルドするとパフォーマンスの低下はゼロになります。
これは、管理可能なコードをどのように書くのが最適かについての質問のようです。私の新しい信念は、あなたはあなたのコードのすべての消費者の無知を仮定しなければならないということです。私または自分の深い知識を持つ人が私のコードを消費すると想定して、私はトラブルに巻き込まれました。例外のスローに追加する唯一のものは、カスタム例外を作成することと、内部例外にブレッドクラムを残すことです。特にデータが原因である場合、開発者に問題を解決する機会を与えることを強く信じています。私はほとんどの時間をコードを壊すデータを探すのに費やします。ヒントを残せば、1年で数週間節約できます。
まず第一に、あなたは間違いなく間違いです。あなたは非常に深刻な論理的誤fallを受け入れています。あなたは、その周りで起こっているすべてが正しいと仮定しているコードのおかげで、あなたのコードが正しいことを望んでいます。あたかも正解は魔法の妖精の粉塵のようなもので、あちこちにスプレーするだけです。
すべてのバグは、公開されると愚かであるか、または愚かに見える。しかし、このようなチェックは、それらをからかって自分自身を公開します。それまで、バグは目に見えません。また、大規模で複雑なプロジェクトの場合、誰がバグを見つけるのか、どのような条件でバグが見つかるのかわかりません。復元力を考慮して設計されたコードは通常、このようなチェックを全面的に行い、エラー値を含める必要があるすべての関数の戻り値もチェックします。したがって、「私が依存しているサブ機能が機能していないため、「私はそれができません」をエンコードすることになります」実際に適切に処理されるセマンティック。これの大きな価値は、通常、回避策または自己認識デバッグ計装を非常に簡単に実装できることです。このようなことをしたいのは、なぜ最も難しいバグは通常、これらのプロパティの両方に依存して適切にデバッグするためです。
開発者からいくつかの教訓を学びます。彼らはそのようなチェックをそこに置きます。なぜなら、なぜ関数から奇妙な結果が得られるのかわからないからです。あなたは彼らが持っていないというあなたの持っている狭い知識の一つのために、あなたは彼らを素朴または過度に用心深いと呼びます。しかし、厄介なものをデバッグしているとき、なぜコードにそのようなチェックがないのか不思議に思うでしょう。そして、バグを最初に見つけられないのと同じように素朴に見えてしまいます。
簡単に言うと、周囲の環境の堅牢性を前提としたコードは堅牢になりません。