作为用户,我有一个自定义集合
IList<user>
。当我尝试检查 users
是否为空或为空时,我没有得到任何智能帮助(如 IsNullOrEmpty
),所以我编写了以下扩展方法
public static bool IsNullOrEmpty<T>(this IEnumerable<T> source)
{
if (source.IsNullOrEmpty())
{
return true;
}
return false;
}
令我惊讶的是,我发现
IEnumerable<T>
有IsNullOrEmpty()
。
据我所知,
IList
延伸了ICollection
,又延伸了IEnumerable
,如果是这样的话,那么IList
应该支持IsNullOrEmpty
。
有错误的地方请指正。
IEnumerable<T>
没有 IsNullOrEmpty
方法,它是您上面编写的扩展。如果你调用它,你会得到一个 StackOverflowException
。
你可以这样实现:
public static bool IsNullOrEmpty<T>(this IEnumerable<T> source)
{
return source == null || !source.Any();
}
但需要注意的是,这种方法的帮助并不大,甚至会变得更糟。因为
Enumerable.Any
会“消耗”查询。因此,如果它不是内存中的集合,则必须调用 GetEnumerator
并开始枚举它,以便检查是否至少有一项。有时,如果对象被枚举,该对象将被释放(例如 .NET 中的 File.ReadLines
<= 4) which willl cause an ObjectDisposedException
,如果您稍后尝试再次使用它)。
此方法具有不需要的副作用的另一个示例是当序列是过滤的查询时(
...Where(x => Compute(x, random.Next()))
)。此查询每次可能会产生不同的结果。引用 Marc Gravell 的评论:“IEnumerable 不应被假定为可重复的”。
在 Linq-To-Sql 或 Linq-To-Entities 中,您将在每次
IsNullOrEmpty
调用时调用数据库。
正如@Marc Gravel 在评论中提到的“
IEnumerable<T>
不应被假定为可重复的”。假设您的源 IEnumerable
是从数据读取器创建的。你只有一次机会迭代它。如果您只是为了查看它是否为空而消耗了唯一的机会,那么您将无法再次访问记录。也许您想为 IList
编写扩展方法(如果需要),而不是为 IEnumerable
。
public static bool IsNullOrEmpty<T>(this IList<T> source)
{
return source == null || source.Count == 0;
}