web-dev-qa-db-ja.com

Any()がc#nullオブジェクトで動作しないのはなぜですか

Nullオブジェクトで Any() を呼び出すと、C#でArgumentNullExceptionがスローされます。オブジェクトがnullの場合、間違いなく「any」は存在せず、おそらくfalseを返すはずです。

C#がこのように動作するのはなぜですか?

42

参照型を扱う場合、null値は「空の」値と意味的に異なります。

null文字列はstring.Emptyと同じではなく、nullIEnumerable<T>Enumerable.Empty<T>(またはその他の「空の」列挙可能)とは異なります。そのタイプの)。

Anyが拡張メソッドでない場合、nullで呼び出すとNullReferenceExceptionになります。それは拡張メソッドであるため、いくつかの例外をスローすることは(必要ではありませんが)良いアイデアですnullのメソッド:BOOM!

37
Jon

Any()からの質問:「このボックスにはアイテムが含まれていますか?」

ボックスが空の場合、答えは明らかに「いいえ」です。

しかし、そもそもボックスがなければ、質問は意味をなさず、関数は「一体何のことを言っているのですか?ボックスはありません」と文句を言います。

127
CodesInChaos

最新のC#では、次のような簡単なチェックでOPのシナリオを簡単に処理できます。

_List<string> foo = null;

if (foo?.Any() ?? false)
{
    DoStuff();
}
_

これは、OPがAnyOrDefault(bool default)拡張メソッドが行うことを期待している不完全なAny()実装のようなものです。

これを次のような拡張機能に簡単に作成できます。

_public static bool HasItems<T>(this IEnumerable<T> source)
{
    return (source?.Any() ?? false);
}
_

正直なところ、デフォルト値を渡すのは理にかなっていないため、AnyOrDefaultという名前はあまり好きではありません(デフォルトのtrueは、おそらく後でコードを読む人にとってはかなり意味があるでしょう)。 コメントで提案されているように、HasItemsに名前が変更されました。これははるかに良い名前です!

32
Jaxidian

Any()は拡張メソッドであるため、thisは実際にはメソッドの最初の引数として渡されます。この状況では、ArgumentNullException is this is nullをスローすることは理解できます。

事前に自分でチェックを実行できます。

bool hasAny = yourData == null ? false : yourData.Any(yourPredicate);
4

Any()は次のような拡張メソッドであるため:

public static bool Any(this IEnumerable enumerable)
{
    if (enumerable == null)
        throw ArgumentNullException("enumerable");
    ...
}
2
roxioam

AnyメソッドはIEnumerableに対して実行され、アイテムがあるかどうかを示しますEnumerable内。列挙するものを何も与えない場合、ArgumentNullExceptionは妥当です。(一致する)要素のないコレクションは、コレクションがないと異なります。

1
Dan Puzey

他の人が既に述べたように、Anyはシーケンスに要素が含まれているかどうかをチェックします。 null値を渡すことを妨げません(そもそもバグの可能性があります)。

Enumerable class のすべての拡張メソッドは、ArgumentNullExceptionsourceの場合、 null をスローします。拡張機能でArgumentNullExceptionsをスローするのは、実際には 適切な練習 です。

1
Tim Schmelter