ある種のオブジェクトを引数として取るメソッドがあるとします。ここで、このメソッドにnull引数が渡された場合、致命的なエラーであり、例外をスローする必要があると言います。次のようなコードを書くことは価値がありますか(これは簡単な例です)。
void someMethod(SomeClass x)
{
if (x == null){
throw new ArgumentNullException("someMethod received a null argument!");
}
x.doSomething();
}
または、x.doSomething()を呼び出すときにNullExceptionをスローするだけに依存しても安全ですか?
次に、someMethodがコンストラクターであり、xは別のメソッドが呼び出されるまで使用されないと仮定します。すぐに例外をスローするか、xが必要になるまで待ってから例外をスローする必要がありますか?
引数をチェックしないと提供されるArgumentNullException
よりもNullReferenceException
の方が好きです。一般に、私の好みは、潜在的にヌルのオブジェクトでメソッドを呼び出そうとする前に、常にヌルをチェックすることです。
メソッドがコンストラクターである場合、いくつかの異なる要因に依存します。プロパティのパブリックセッターもあり、オブジェクトが実際に使用される可能性はどれくらいか。パブリックセッターが存在する場合、コンストラクターを介して有効なインスタンスを提供しないことは合理的であり、例外は発生しません。
パブリックセッターがなく、挿入されたオブジェクトを参照せずに包含オブジェクトを使用できる場合、その使用が試行されるまでチェック/例外を延期することができます。ただし、一般的なケースは、注入されたオブジェクトがインスタンスの機能に不可欠であり、したがってインスタンスがそれなしでは機能できないため、ArgumentNull例外は完全に合理的だと思います。
私は常にfail fastのプラクティスに従います。メソッドがXに依存しており、Xがnullで渡される可能性があることを理解している場合、障害点を延長する代わりに、nullをチェックし、すぐに例外を発生させます。
2016アップデート:
実世界の例。 Jetbrains Annotations の使用を強くお勧めします。
[Pure]
public static object Call([NotNull] Type declaringType,
[NotNull] string methodName,
[CanBeNull] object instance)
{
if (declaringType == null) throw new ArgumentNullException(nameof(declaringType));
if (methodName == null) throw new ArgumentNullException(nameof(methodName));
ガードステートメントは、C#6がnameof
演算子を提供することで大幅に改善されました。
これらの理由から、明示的な例外を好みます。
私は速く失敗するという考えに同意しますが、なぜ速く失敗することが実用的であるかを知ることは賢明です。この例を考えてみましょう:
void someMethod(SomeClass x)
{
x.Property.doSomething();
}
NullReferenceException
に依存して何かがおかしいと言った場合、nullが何であるかをどのようにして知ることができますか?スタックトレースは行番号のみを提供し、どの参照がnullであったかは提供しません。この例では、x
またはx.Property
の両方がnullであった可能性があり、事前にアグレッシブなチェックを行うことで迅速に失敗することなく、どちらであるかがわかりません。
明示的なArgumentNullExceptionを使用したパラメーターチェックもお勧めします。
メタデータを見る:
//
// Summary:
// Initializes a new instance of the System.ArgumentNullException class with
// the name of the parameter that causes this exception.
//
// Parameters:
// paramName:
// The name of the parameter that caused the exception.
public ArgumentNullException(string paramName);
文字列はパラメータの名前である必要があり、nullであることがわかります。そのため、開発者に何が間違っているのかというヒントを与えてください。
ArgumentNullExceptionをスローするよりも早くスローすることをお勧めします。投げた場合は、NullReferenceExceptionよりも問題に関する役立つ情報を提供できます。
入力がnullでないことが予想される場合は、ArgumentNullExceptionを明示的にスローする必要があります。このためのヘルパーメソッドを提供するGuardというクラスを作成することもできます。したがって、コードは次のようになります。
void someMethod(SomeClass x, SomeClass y)
{
Guard.NotNull(x,"x","someMethod received a null x argument!");
Guard.NotNull(y,"y","someMethod received a null y argument!");
x.doSomething();
y.doSomething();
}
NonNullメソッドはnullityチェックを行い、呼び出しで指定されたエラーメッセージでNullArgumentExceptionをスローします。
1- Null値が必要ない場合は、明示的に実行します。それ以外の場合、他の誰かがあなたのコードを見るとき、彼らはNull値を渡すことが受け入れられると考えます。
2-できる限り迅速に実行します。この方法では、想定されていない場合にNullを使用する「間違った」動作を伝播しません。
防御的にプログラムする場合、高速で失敗するはずです。そのため、コードの先頭で入力とエラーを確認してください。あなたはあなたの呼び出し元に親切であり、あなたにできる限り最も説明的なエラーメッセージを与えるべきです。
次のような構文を使用して、ArgumentNullException
をスローするだけでなく、エラーテキストの一部としてその例外にパラメーター名を付けることもできます。例えば。;
void SomeMethod(SomeObject someObject)
{
Throw.IfArgNull(() => someObject);
//... do more stuff
}
例外を発生させるために使用されるクラスは次のとおりです。
public static class Throw
{
public static void IfArgNull<T>(Expression<Func<T>> arg)
{
if (arg == null)
{
throw new ArgumentNullException(nameof(arg), "There is no expression with which to test the object's value.");
}
// get the variable name of the argument
MemberExpression metaData = arg.Body as MemberExpression;
if (metaData == null)
{
throw new ArgumentException("Unable to retrieve the name of the object being tested.", nameof(arg));
}
// can the data type be null at all
string argName = metaData.Member.Name;
Type type = typeof(T);
if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
{
throw new ArgumentException("The expression does not specify a nullible type.", argName);
}
// get the value and check for null
if (arg.Compile()() == null)
{
throw new ArgumentNullException(argName);
}
}
}
私はおそらくこれに落胆するでしょうが、私は完全に違うと思います。
"never pass null"と呼ばれる良い慣習に従って、い例外チェックを削除するのはどうですか?
パラメータがオブジェクトの場合、NULLを渡さないでください。また、NULLを返さないでください。 Nullオブジェクトパターンを使用して、それを支援することもできます。
オプションの場合は、デフォルト値を使用するか(言語でサポートされている場合)、オーバーロードを作成します。
Exceptionい例外よりもずっときれいです。