【IT168技术】Linq 出现之前,我们通常使用下面的方式来判断集合是否非空,即集合包含元素:
1 var array = new int[0];
2 var b1 = array.Length > 0;
3 var list = new List<string>();
4 var b2 = list.Count > 0;
5 var collection = new Collection<double>();
6 var b3 = collection.Count > 0;
2 var b1 = array.Length > 0;
3 var list = new List<string>();
4 var b2 = list.Count > 0;
5 var collection = new Collection<double>();
6 var b3 = collection.Count > 0;
使用 Length 或 Count 属性,上面的写法没有问题。
但到了 Linq 时代,Enumerable.Count 扩展方法“统一了“ Length 和 Count 属性,于是就有了下面判断非空的写法:
1 public static void SomeAction<T>(IEnumerable<T> source){
2 if (source.Count() > 0){
3 //...
4 }//...
5 }
2 if (source.Count() > 0){
3 //...
4 }//...
5 }
这种写法可以,运行也正常,但可能会产生非常严重的性能的问题。
注意是可能,并不是一定,上面的方法如果传入的是 Array、List或Collection,不会有问题。
那么什么时候会出问题呢?我们来看如下方法:
1 public static IEnumerable<int> GetNums(int start, int count)
2 {
3 var end = start + count;
4 for (int i = start; i < end; i++)
5 yield return i;
6 }
2 {
3 var end = start + count;
4 for (int i = start; i < end; i++)
5 yield return i;
6 }
如下调用时:
var nums = GetNums(0, int.MaxValue);
SomeAction(nums);
SomeAction(nums);
执行速度会相当慢,我的电脑大约用了 70 秒的时间来执行 source.Count() > 0。
分析下的话,你会发现 GetNums 第 5 行代码 yield return i 执行了 int.MaxValue 次,有必要吗?
其实只要返回一个元素我们就可以断定集合非空,完全不需要将所有的元素返回。
那又如何来判断呢?我们可以使用 Enumerable.Any 扩展方法:
将 SomeAction 方法修改如下:
1 public static void SomeAction<T>(IEnumerable<T> source){
2 if(source.Any()){ // 切勿使用 source.Count() > 0
3 //...
4 }//...
5 }
2 if(source.Any()){ // 切勿使用 source.Count() > 0
3 //...
4 }//...
5 }
再次调用 ,你会发现执行时间可以忽略不计了。
总结下规律, Count() > 0 遇上 yeild return 必定会出现性能问题。
Enumerable.Any 扩展方法可以解决我们的问题,但这个方法在命名上似乎有些问题,总感觉有点不顺,如若判断集合为空:
if (!source.Any()) { //...
}
}