在空对象上调用Any()时,它会在 C# 中引发 ArgumentNullException。如果对象为空,则肯定没有“任何”,它可能应该返回 false。
为什么 C# 会这样?
在空对象上调用Any()时,它会在 C# 中引发 ArgumentNullException。如果对象为空,则肯定没有“任何”,它可能应该返回 false。
为什么 C# 会这样?
Any()
正在问:“这个盒子里有什么东西吗?”
如果盒子是空的,答案显然是否定的。
但是如果一开始就没有盒子,那么这个问题就没有意义了,函数就会抱怨:“你到底在说什么?没有盒子。”
当我想将丢失的集合视为空集合时,我使用以下扩展方法:
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> sequence)
{
return sequence ?? Enumerable.Empty<T>();
}
这可以与所有 LINQ 方法结合使用foreach
,而不仅仅是.Any()
.
使用现代 C#,您可以通过如下简单检查轻松处理 OP 场景:
List<string> foo = null;
if (foo?.Any() ?? false)
{
DoStuff();
}
这有点像AnyOrDefault(bool default)
OP 期望Any()
扩展方法执行的蹩脚实现。
你可以很容易地把它变成这样的扩展:
public static bool HasItems<T>(this IEnumerable<T> source)
{
return (source?.Any() ?? false);
}
老实说,我真的不喜欢这个名字AnyOrDefault
,因为传递默认值是没有意义的(默认值 true 可能对以后阅读代码的人来说是非常卑鄙的)。HasItems
按照评论中的建议重命名为。这是一个更好的名字!
在处理引用类型时,null
值在语义上与“空”值不同。
字符串null
与 不同string.Empty
,并且 anull
IEnumerable<T>
与 Enumerable.Empty<T>
(或该类型的任何其他“空”可枚举)不同。
如果Any
不是扩展方法,则调用它null
会导致NullReferenceException
. 由于它是一种扩展方法,因此抛出一些异常(尽管不是必需的)是一个好主意,因为它保留了尝试调用方法的众所周知的语义null
:BOOM!
Any()
是一个扩展方法,所以this
实际上是作为方法的第一个参数传递的。在这种情况下,它抛出ArgumentNullException
is this
is 是可以理解的null
。
您可以事先自行执行检查:
bool hasAny = yourData == null ? false : yourData.Any(yourPredicate);
因为 Any() 它是这样的扩展方法:
public static bool Any(this IEnumerable enumerable)
{
if (enumerable == null)
throw ArgumentNullException("enumerable");
...
}
该Any
方法针对 an 运行并告诉您Enumerable 中IEnumerable
是否有任何项目。如果您不给它任何枚举,那么 ArgumentNullException 是合理的:没有(匹配)元素的集合与没有集合不同。
正如其他人已经提到的,Any
检查序列是否包含元素。它不会阻止您传递null
值(首先可能是什么错误)。
Enumerable
类中的每个扩展方法都会抛出一个ArgumentNullException
if the source
is null
。加入ArgumentNullExceptions
扩展实际上是一种很好的做法。
Any()
是一个扩展方法,ArgumentNullException
如果源为空则抛出。你会什么都不做吗?通常,最好获得一些关于代码中正在发生的事情的明确指示,而不是默认值。
但这并不意味着它不能那样。如果您知道自己在做什么,请编写自己的自定义实现。
我只是想与您分享一些我公司正在遵循的实用建议。我们编写与私有 NuGet 共享的自定义包,这些包在我们的产品中广泛使用。检查列表是否为空/空是非常频繁的,因此我们决定编写我们的实现以Any
使我们的代码更短更简单。