[英]Why doesn't Any() work on a c# null object
When calling Any() on a null object, it throws an ArgumentNullException in C#. If the object is null, there definitely aren't 'any', and it should probably return false.在 null object 上调用Any()时,它会在 C# 中抛出 ArgumentNullException。如果 object 是 null,则肯定没有“任何”,它可能应该返回 false。
Why does C# behave this way?为什么 C# 会这样?
Any()
is asking: "Does this box contain any items?" Any()
在问:“这个盒子里有任何物品吗?”
If the box is empty, the answer is clearly no.如果盒子是空的,答案显然是否定的。
But if there is no box in the first place, then the question makes no sense, and the function complains: "What the hell are you talking about? There is no box."但是如果一开始就没有盒子,那么这个问题就没有意义了,函数就会抱怨:“你到底在说什么?没有盒子。”
When I want to treat a missing collection like an empty one, I use the following extension method:当我想将丢失的集合视为空集合时,我使用以下扩展方法:
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> sequence)
{
return sequence ?? Enumerable.Empty<T>();
}
This can be combined with all LINQ methods and foreach
, not just .Any()
.这可以与所有 LINQ 方法和
foreach
结合,而不仅仅是.Any()
。
With modern C#, you can easily handle the OP's scenario with a simple check like this:使用现代 C#,您可以通过如下简单检查轻松处理 OP 场景:
List<string> foo = null;
if (foo?.Any() ?? false)
{
DoStuff();
}
This is kinda like a lame AnyOrDefault(bool default)
implementation that the OP is expecting the Any()
extension method to do.这有点像 OP 期望
Any()
扩展方法执行的蹩脚的AnyOrDefault(bool default)
实现。
You could easily make this into an extension like this:你可以很容易地把它变成这样的扩展:
public static bool HasItems<T>(this IEnumerable<T> source)
{
return (source?.Any() ?? false);
}
Honestly, I don't really like the name AnyOrDefault
for this since it won't ever make sense to pass in a default value (a default of true would probably be pretty mean to people reading code later).老实说,我真的不喜欢 Renamed to AnyOrDefault
这个名字,因为传递默认值是没有意义的(默认值 true 可能对以后阅读代码的人来说是非常卑鄙的)。HasItems
, as suggested in the comments.根据评论中的建议,重命名为
HasItems
。 This is a far better name!这是一个更好的名字!
When dealing with reference types, a null
value is semantically different from an "empty" value.在处理引用类型时,
null
值在语义上与“空”值不同。
A null
string is not the same as string.Empty
, and a null
IEnumerable<T>
is not the same as Enumerable.Empty<T>
(or any other "empty" enumerable of that type). null
字符串与string.Empty
不同,并且null
IEnumerable<T>
与Enumerable.Empty<T>
(或该类型的任何其他“空”可枚举)不同。
If Any
were not an extension method, calling it on null
would result in NullReferenceException
.如果
Any
不是扩展方法,则在null
上调用它会导致NullReferenceException
。 Since it is an extension method, throwing some exception (although not necessary) is a good idea because it preserves the well-known semantics of trying to call a method on null
: BOOM!由于它是一种扩展方法,因此抛出一些异常(尽管不是必需的)是一个好主意,因为它保留了尝试在
null
上调用方法的众所周知的语义: BOOM!
Any()
is an extension method, so this
is actually passed as the first argument to the method. Any()
是一个扩展方法,所以this
实际上是作为该方法的第一个参数传递的。 In this situation, it's understandable for it to throw ArgumentNullException
is this
is null
.在这种情况下,它抛出
ArgumentNullException
is this
is null
是可以理解的。
You can perform the check yourself beforehand:您可以事先自行执行检查:
bool hasAny = yourData == null ? false : yourData.Any(yourPredicate);
Because Any() it is a extension method like this:因为 Any() 它是这样的扩展方法:
public static bool Any(this IEnumerable enumerable)
{
if (enumerable == null)
throw ArgumentNullException("enumerable");
...
}
The Any
method runs against an IEnumerable
and tells you whether there are any items in the Enumerable . Any
方法针对IEnumerable
运行,并告诉您Enumerable 中是否有任何项目。 If you don't give it anything to enumerate then an ArgumentNullException is reasonable: a collection with no (matching) elements is different to no collecion.如果您不给它任何枚举,那么 ArgumentNullException 是合理的:没有(匹配)元素的集合与没有集合不同。
As others have already mentioned, Any
checks whether or not a sequence contains elements.正如其他人已经提到的,
Any
检查序列是否包含元素。 It does not prevent you from passing null
values(what might the bug in the first place).它不会阻止您传递
null
值(首先可能是什么错误)。
Every extension method in Enumerable
class throws an an ArgumentNullException
if the source
is null
.如果
source
为null
,则Enumerable
类中的每个扩展方法都会引发ArgumentNullException
。 Throwing ArgumentNullExceptions
in extensions actually is good practise .在扩展中抛出
ArgumentNullExceptions
实际上是一种很好的做法。
Any()
is an extension method that throws ArgumentNullException
if the source is null. Any()
是一种扩展方法,如果源为 null,则抛出ArgumentNullException
。 Would you perform an action on nothing?你会什么都不做吗? In general, it's better to get some explicit indicator of what's happening in the code rather than the default value.
通常,最好获得一些关于代码中正在发生的事情的明确指示,而不是默认值。
But it doesn't mean it can't be like that.但这并不意味着它不能那样。 If you know what you doing, write your own custom implementation.
如果您知道自己在做什么,请编写自己的自定义实现。
I just wanted to share with you some practical advice my company is following.我只是想与您分享一些我公司正在遵循的实用建议。 We write our custom packages shared with private NuGet that are widely used in our products.
我们编写与私有 NuGet 共享的自定义包,这些包在我们的产品中广泛使用。 Checking if the list is null/empty is very frequent, so we decided to write our implementation of
Any
which makes our code shorter and simpler.检查列表是否为空/空是非常频繁的,因此我们决定编写
Any
的实现,这使得我们的代码更短更简单。
Any()
internally attempts to access the underlying sequence ( IEnumerable
). Any()
在内部尝试访问底层序列( IEnumerable
)。 Since the object can be null , there is no way to access the enumerable to validate it, hence a NullReferenceException
is thrown to indicate this behavior.由于对象可以为null ,因此无法访问可枚举来验证它,因此会抛出
NullReferenceException
来指示此行为。
At first, it sounds like it should just return false since null in a way could mean none.起初,听起来它应该只返回 false,因为 null 在某种程度上可能意味着没有。
However, there is different levels of information and behavior occurring here.但是,这里发生了不同级别的信息和行为。
Any()
with 0 elements is a collection with 0 elements.Any()
是具有0个元素的集合。null
means no collection. null
表示不收集。 Any()
with 0
elements is a collection.具有
0
个元素的Any()
是一个集合。 The latter isn't a collection.后者不是一个集合。
If you have a wallet (underlying sequence), with no cash (elements) inside, you have a wallet, but your broke (no elements).如果你有一个钱包(底层序列),里面没有现金(元素),你有一个钱包,但是你破产了(没有元素)。 Null means you don't even have a wallet to put cash inside.
Null 意味着您甚至没有钱包可以放入现金。
There is a method in the.Net Framework for this, why they hid it here, who knows... .Net Framework 中有一个方法,为什么他们把它藏在这里,谁知道......
namespace Microsoft.IdentityModel.Tokens
{
/// <summary>
/// A class which contains useful methods for processing collections.
/// </summary>
public static class CollectionUtilities
{
/// <summary>
/// Checks whether <paramref name="enumerable"/> is null or empty.
/// </summary>
/// <typeparam name="T">The type of the <paramref name="enumerable"/>.</typeparam>
/// <param name="enumerable">The <see cref="IEnumerable{T}"/> to be checked.</param>
/// <returns>True if <paramref name="enumerable"/> is null or empty, false otherwise.</returns>
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
return enumerable == null || !enumerable.Any();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.