在C#中,当对一个空对象调用Any()方法时,会抛出一个ArgumentNullException异常。如果对象为空,则显然没有“任何”东西,应该返回false。
为什么C#会这样表现呢?
在C#中,当对一个空对象调用Any()方法时,会抛出一个ArgumentNullException异常。如果对象为空,则显然没有“任何”东西,应该返回false。
为什么C#会这样表现呢?
Any()
的意思是:“这个盒子里有没有物品?”
如果盒子是空的,答案显然是否定的。
但是如果一开始就没有盒子,那么这个问题就没有意义,该函数会抱怨:“你在说什么东西?根本就没有盒子。”
当我想将一个缺失的集合视为一个空集合时,我使用以下扩展方法:
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> sequence)
{
return sequence ?? Enumerable.Empty<T>();
}
这可以与所有LINQ方法和foreach
结合使用,而不仅仅是.Any()
。
?.Any() ?? false
或者?.Any() == true
。另外,如果你想使用我答案中提供的扩展方法,可以使用.OrEmpty().Any()
。 - CodesInChaospublic static bool IsNullOrEmpty<T>(this IEnumerable<T> list) => list == null || !list.Any();
- azurez27使用现代的 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
。这是一个更好的名称!
if (foo?.Any() == true)
比 .. ?? false)
更容易理解。前者在英语中的意思是 "如果有任何一个为真,则执行…",而后者本质上是一个两步逻辑语句,更难以用简单的话来表述。它的意思类似于 "如果有任何一个(但将 null 视为 false)为真,则执行…"。 - ToolmakerSteveAnyOrDefault
的替代名称可能是 HasItems
或更明确的 AnyAndNotNull
。另外,"Default" 在你的 AnyOrDefault
中指的是源类型的默认值,例如 IEnumerable 的默认值为 "null",与布尔值的默认值 "false" 无关。因此,这个名称是具有误导性的,因为 AnyOrDefault
在逻辑上应该意味着 "任何一个或 null(因为那是默认值)",所以会对 null 返回 true
。显然这不是你的意思。 - ToolmakerSteveHasItems()
,无论是空列表还是null,名称仍然正确。 - Pawel Cioch处理引用类型时,null
值在语义上与“空”值不同。
null
字符串与 string.Empty
不同,而 null
的 IEnumerable<T>
也不同于 Enumerable.Empty<T>
(或该类型的任何其他“空”枚举)。
如果 Any
不是扩展方法,则在 null
上调用它将导致 NullReferenceException
。因为它是扩展方法,所以抛出一些异常(虽然不是必需的)是一个好主意,因为它保留了尝试在 null
上调用方法的众所周知的语义:BOOM!
(Source?.Any()).GetValueOrDefault()
来进行简单的空值检查或者在strict on
场景下判断不存在性...这是Linq团队的一个糟糕决定:他们应该时刻记住,他们的东西是为那些知道自己在做什么的人而设计的,而不是像我这样毫无头绪的人! :/ - ShockwaverAny()
是一个扩展方法,所以 this
实际上被作为第一个参数传递给该方法。在这种情况下,如果 this
为 null
,那么抛出 ArgumentNullException
是可以理解的。
您可以事先进行检查:
bool hasAny = yourData == null ? false : yourData.Any(yourPredicate);
因为Any()是一个像这样的扩展方法:
public static bool Any(this IEnumerable enumerable)
{
if (enumerable == null)
throw ArgumentNullException("enumerable");
...
}
Any
方法针对IEnumerable
运行,告诉您在可枚举集合中是否存在任何项。如果您没有给它任何要枚举的内容,则引发ArgumentNullException异常:不包含(匹配的)元素的集合与没有集合不同。请注意保留HTML标记。Any()
首先内部检查source是否为null
,如果是,则抛出ArgumentNullException
(在这种情况下不返回bool)。否则,它尝试访问基础序列(IEnumerable
)。如果序列中至少存在一个元素,则返回true,否则返回false。需要注意的是,在技术上有三个返回值,true/false + 抛出可以捕获的ArgumentNullException
(在技术上也算一种返回)。
起初,如果source
为null,似乎应该只返回false,因为从某种意义上来说可能表示没有元素。
然而,这里涉及到不同级别的信息和行为。没有元素和null真正意味着什么?
Any()
的行为true
。false
。NullReferenceException
异常。null
在所有情境下都表示什么都没有;没有数据,没有内存指针。 null
不是一个集合,也不是一个对象。它代表了内存中的缺失。当计算机“读取内存”时,它试图从特定位置读取存储在内存中的值。如果内存读取操作遇到特殊的空字符,即“空终止符”\0
,CPU 就知道它无法读取内存中的这部分内容。Null 还意味着没有内存来描述某种对象或值。在您的示例中,您调用 Any()
的基础 IEnumerable
对象不存在,只有一个空终止符 \0
。尝试读取仅包含空终止符的内存地址将引发致命异常。如果未处理,NullReferenceException
将按照操作系统或其他软件层(位于您运行的应用程序正下方)定义的方式终止每个程序。
0
个元素的集合执行 Any()
仍然是一个集合。null
不是集合、对象或值。只是什么都没有。如果你有一个可以装钱的钱包(基础序列),但里面没有现金(元素),那么你有一个钱包,但是你很穷(没有元素)。Null 意味着你甚至没有一个可以放现金的钱包。钱包和现金都不存在。
试图访问不存在的东西应该会导致程序崩溃,因为这是不可能的。不可能的事情无法执行。在许多语言中,这是正确的。
正如 @msteel9999 所提到的,在任何一种情况下,你仍然很穷。:D
正如其他人已经提到的那样,Any
检查序列是否包含元素。它不会阻止您传递null
值(这可能是第一次出现错误)。
Enumerable
类中的每个扩展方法都会在source
为null
时抛出ArgumentNullException
。在扩展中抛出ArgumentNullExceptions
实际上是良好的做法。
在 .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();
}
}
}
Any()
是一个扩展方法,如果源为空,则会抛出 ArgumentNullException
。你会对空值执行操作吗?一般来说,在代码中获得一些明确的指示比默认值更好。
但这并不意味着它不能这样。如果你知道自己在做什么,可以编写自己的自定义实现。
我只是想与您分享我们公司正在遵循的一些实用建议。我们编写了自定义包,共享私有 NuGet,这些包广泛用于我们的产品中。检查列表是否为空非常频繁,因此我们决定编写自己的 Any
实现,使我们的代码更短、更简单。
.Any()
之前手动进行检查很笨拙。 - Thomas Mulder