4

If null チェックを常に入れている開発者が何人かいます

例えば:

Run(Order order)
{
  if (order == null) return;
}

誰かがnullのパラメーターを渡した場合、クラスを保護していると考えているため、コード内で。この場合、誰かが null を渡している場合、おそらく消費者コードの問題であり、このクラスが例外をスローして高速に失敗する代わりに、ロジックの欠陥を伝えようとしています。消費者と一気飲みし続けます。

もう 1 つの提案は、高速に失敗して例外をスローする前提条件またはガード クラスを用意することです。消費者がおそらく他の問題を抱えているという事実を無視する以外のことは何でも、私はそれを隠すのに役立ちます.

あなたのクラスはそれほど寛容であってはならないという事実を人々に理解してもらうにはどうすればよいでしょうか。誰かが良いデータを渡さなかった場合は、そのことを知らせる必要があります。

この点を理解するのに役立つ良い記事や提案はありますか?

4

9 に答える 9

13

クラスが引数を受け入れられない場合null、最善の方法は次のとおりです。

if (arg == null)
    throw new ArgumentNullException();

NullPointerExceptionこれは、スタックを深く掘り下げるよりもはるかに望ましい方法です。最悪のシナリオでは、それをnullどこかにキャッシュし、実際にはずっと後まで例外をトリガーせず、問題のデバッグがどれほど楽しいかを確認します

そして、他の人が述べたように、契約はそれnullでいいと言っていることがあります。その場合、コードの一部にガード句を配置することは正しいことですが、その場合でも、最適な設計は、オプションで null の引数を使用せずにオーバーロードを追加することだと思います。

于 2009-10-30T02:30:57.360 に答える
7

それは本当に正確な状況に依存します。あなたが示しているように、「コードにnullチェックを入れないでください」のような一般的な提案をすることはめったに勧められません。クラスのコントラクトは、正当なものとそうでないものを定義する必要があります。しかし、null を渡すことが受け入れられないことが契約で明確にされている場合、例外は実際に適切な応答です。

于 2009-10-30T02:26:49.997 に答える
3

他の誰もが言っているように、本番環境で不可解な問題が発生するよりも、早い段階で失敗する方がはるかに望ましいのです。あなたの例のように、関数が null 引数を返す場合)。

関数が値を返さずに をスローするだけNullReferenceExceptionの場合でも、引数が null であることがわかっていると、バグを解決しやすくなります。関数が をスローした場合、NullReferenceException何が原因でnull、誰のせいだったのかわかりません。

ArgumentNullException理由により、パラメーターを取ることを追加したいと思います。

書いたほうがいい

if(myArg == null) throw new ArgumentNullException("myArg");

ArgumentNullExceptionなしで を投げるよりもparamName

このようにして、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$");
        $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>
于 2009-10-30T02:50:17.127 に答える
2

私はそれを見ていませんが、eiffel.com には契約による設計のトピックに関する 2 つのプレゼンテーション (スライド + オーディオ) があります。これらの人は概念を発明したので、誰かがそれを説明できるなら、それは彼らです:-)

于 2009-10-30T02:28:53.353 に答える
2

.net 4.0 のコード コントラクトにより、この動作の一貫性が大幅に向上することが期待されます。コード コントラクトについて説明する記事は、アイデアを理解するのに役立ちます。将来的には、この種の構文がメソッドを提供します。

http://blogs.msdn.com/bclteam/archive/2008/11/11/introduction-to-code-contracts-melitta-andersen.aspx

于 2009-10-30T02:36:27.607 に答える
1

このような慣習がなぜ間違っているのかを人々に伝えることができない場合があります。彼らは自分でそれを理解する必要があります。しかし、この問題が原因で厄介な失敗を引き起こす単体テストを考え出し、エラーをデバッグさせることで、彼らがそこに到達するのを助けることができます。

于 2009-10-30T02:53:22.190 に答える
1

メソッドのコントラクトで引数がnullであってはならないことが指定されている場合、正しいことは、次のようにAssertを使用して明示的にすることです。

Debug.Assert( item != null, "Null items are not supported );

これは、実行可能ファイルがデバッグ構成を使用してビルドされた場合はすぐに失敗しますが、リリース構成を使用してビルドされた場合はパフォーマンスの低下はありません。

于 2009-10-30T02:58:40.493 に答える
1

これは、扱いやすいコードをどのように書くのが最善かという問題のようです。コードのすべての消費者が無知であることを想定しなければならないというのが、私の新しい信念です。私または深い知識を持つ誰かが私のコードを消費すると仮定して、私はトラブルに巻き込まれました。例外のスローに追加する唯一のことは、カスタム例外を作成し、内部例外にブレッドクラムを残すことです。特にデータが原因である場合は、開発者に問題を解決する機会を与えることを強く信じています. 私は自分のコードを壊すデータを探すのにほとんどの時間を費やしています。ヒントを残すことができれば、1 年で数週間節約できます。

于 2009-10-30T03:55:05.507 に答える
-2

まず第一に、あなたは明白に間違っています。あなたは非常に深刻な論理的誤謬を受け入れています。あなたは、コードの周りで起こっているすべてが正しいと仮定して、コードのおかげであなたのコードが正しいことを望んでいます。まるで正しさは、どこにでもスプレーする必要があるある種の魔法のピクシーダストであるかのように。

すべてのバグは、一度公開されるとばかげているか、ばかげているように見えます。しかし、このようなチェックは、彼らをからかって彼ら自身を暴露させます。それまでは、バグは見えません。また、大規模で複雑なプロジェクトの場合、誰がバグを見つけるのか、どのような条件下でバグが見つかるのかがわかりません。復元力のために設計されたコードは、通常、このようなチェックがいたるところにあり、エラー値を含める必要があるすべての関数の戻り値もチェックします。したがって、実際に適切に処理される「依存するサブ関数が機能していないため、それを実行できません」というセマンティクスをエンコードすることになります。これの大きな価値は、通常、回避策や自己認識型のデバッグインストルメンテーションを非常に簡単に実装できることです。 なぜこのようなことをしたいのは、最も難しいバグは通常、適切にデバッグするためにこれらのプロパティの両方に依存しているためです。

開発者からいくつかの教訓を学びましょう。なぜ関数から奇妙な結果が得られるのかわからないので、そこにそのようなチェックを入れます。あなたは彼らをナイーブまたは過度に用心深いと呼びます。なぜなら、彼らが持っていないというあなたが持っている1つの狭い知識のためです。しかし、厄介なものをデバッグしているときは、なぜコードにそのようなチェックがないのか疑問に思うでしょう。そして、そもそもバグを見つけることができないのと同じように素朴に見えることになります。

つまり、周囲の環境に関する堅牢性を前提として、コードが堅牢になることはありません。

于 2009-10-30T03:01:27.453 に答える