8

メソッドの引数が null であるかどうかをチェックする (その後、例外をスローする) ことに慣れているので、もうそれについて考えることさえほとんどありません。引数が参照型の場合は、そこにあります。

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

しかし、arg をすぐに使用する場合はどうすればよいでしょうか。とにかくチェックする必要がありますか?つまり、そうしないと、とにかく環境がスローされます (NullReferenceException)。

例えば:

public int DoStuff(object o)
{
    return o.GetHashCode();
}

null チェックを簡単に追加できます。

public int DoStuff(object o)
{
    if(o == null)
        throw new ArgumentNullException(nameof(o));
    return o.GetHashCode();
}

ただし、どちらの場合も例外がスローされます (デバッグ目的で、ほぼ同じ行で)。唯一の違いはタイプです。

質問:単一の参照型引数を持つパブリックメソッドで、引数をすぐに使用する場合でも、それが であるかどうかを確認する必要がありますか?null

4

7 に答える 7

10

2 つの例外タイプがあるため、チェックすることをお勧めします。

  1. 予期しないNullReferenceException- 何かがうまくいかず、独自のルーチンをデバッグする必要があります
  2. ArgumentNullException-引数がnullであり、間違っているのは呼び出し元です(正しく反応するコードではありません)

throwingArgumentNullExceptionは一種の契約です:引数が正しい場合に備えて実行します:

  // An exaggerated example 
  public int DoStuff(SomeObject o) {
    if (o == null)
      throw new ArgumentNullException(nameof(o));
    else if (o.Disposed)
      throw new ArgumentException(nameof(o), "o must not be disposed")  
    else if (o.Id > 100)
      throw new ArgumentOutOfRangeException("Id ...", nameof(o));  

    // o meets the contract, we accept it and thus we guarantee the output

    return o.SomeMethod();
  }

この種の検証は、public ( protected ) メソッドでは一般的です。なぜなら、それらは外部の世界に公開され、任意の引数に直面できるからです。ただし、プライベートメソッドの場合は、コントラクトを省略できます。呼び出し元は、メソッドを実装するクラス内にあります。

于 2016-03-09T13:31:19.600 に答える
0

考慮すべきシナリオがいくつかあります。

  1. メソッドは、独自のプログラムから呼び出されます。null 値は想定していません。どこかでオブジェクトを使用し、それが null の場合でも、状態は変更されます。
  2. メソッドは、独自のプログラムから呼び出されます。null 値は想定していません。null の場合、状態は変更されず、すべての一貫性が維持されます。
  3. メソッドは、ライブラリまたは API を通じて公開されます。不明な開発者 X は、必要なものを指定してメソッドを呼び出します。
  4. 実装中に引数が null ではないことを知りたいだけです。自分とチームメンバーを守るため。

ポイント (1) と (2) は、例外の安全性に関するものです。基本的に、これは、入力に関係なく、データ構造の状態が一貫していなければならないことを示しています。ほとんどの場合、これは簡単なチェックで解決されます。より複雑なシナリオでは、ロールバックまたはより複雑な機械が必要になる場合があります。そう:

  1. データベースに値を追加するnull場合、データベースが台無しになることは望ましくありません。nullもちろん、仮定を確認するだけで値を解決できます。引数が の場合は、それがシナリオを最もよく表してnullいるため、 をスローArgumentNullExceptionします。
  2. 値を期待せずnull、システムの残りの部分に影響を与えないメソッドを呼び出した場合、私は通常、どこかにコメントを入れて自然に任せます。ANullReferenceExceptionはバグの性質について十分に説明してくれます。
  3. API の場合、人々は特定の動作を期待します (例: a ArgumentNullException)。さらに、開発者として、大きくて悪い外部の世界を信頼するべきではないので、とにかく確認する必要があります。
  4. 自分自身とチーム メンバーを保護するだけの場合は、Assertion. アサーションは通常、リリース コードに終わらない (または少なくとも速度に影響を与えない) ように実装され、自動的にブレークポイントをトリガーし、単体テストに失敗します。また、認識しやすいため、コードが肥大化することもありません。

要約すると、どこにでもチェックを入れるだけではありません。コードが判読不能で肥大化する傾向があります。つまり、例外の安全性を確保するためにチェックを入れる場合は、エラーを最もよく説明する例外を使用するのが最善です。

于 2016-03-09T13:53:22.370 に答える
0

変数をすぐに逆参照している場合は、どちらの方法でも議論できると思いますが、それでも ArgumentNullException の方が好きです。何が起こっているかについては、より明確です。例外には、null だった変数の名前が含まれますが、NullReferenceException には含まれません。

于 2016-03-09T13:34:00.703 に答える
0

エラーがどのようにスローされるかではなく、エラーをどのように処理するかに依存すると思います。例が役立ちます。これがあなたが持っているものの代わりにメソッドであると想像してください:

public static int DoStuff(string o) {
    return Int.Parse(o);
}

これさえあれば、特に問題ありません。

public static void main(string[] args)
{
    try {
        Console.Write("Enter a number: ");
        value = DoStuff(Console.ReadLine());
    }
    catch(Exception ex) {
        Console.WriteLine("An exception was thrown.  Contents: " + ex.ToString());
    }
}

いずれにしても、プログラムの流れは同じです。ただし、以下がある場合:

public static void main(string[] args)
{
    try {
        int value = 0;
        do {
            try {
                Console.Write("Enter a non-zero number to stop: ");
                value = DoStuff(Console.ReadLine());
            }
            catch(ArgumentException ex) {
                Console.WriteLine("Problem with input, try again.  Exception message was: " + ex.Message);
                continue; // Or just nothing, will still loop
            }
        } while(value == 0);
    }
    catch(Exception ex) {
        Console.WriteLine("An exception was thrown.  Contents: " + ex.ToString());
    }
}

基本的に、エラー処理がどの例外タイプであるかを気にしない場合、それはおそらく役に立たない余分なコードです。ただし、特定のものを別の方法で処理する場合は、より具体的な種類の例外をテストしてスローする価値がある場合があります。

しかし、パブリック メソッドはプライベート メソッドよりもはるかに重要であるという上記の Dmitry の投稿には同意します。メソッドの署名は、契約のようなものです。強制するのが一番です。

于 2016-03-09T13:46:51.350 に答える
-1

アインシュタインに従ってください。そのコードは、コード行なしで同じことを行いますか? もしそうなら、それを削除するのがおそらく最善です。

于 2016-03-09T13:26:26.167 に答える