“优秀的程序员的标准之一是:编写更易于扩展的代码”
@图片:奥森公园的向日葵 拍摄于2022年7月23日
01
—
问题缘起
上一篇中,我们知道List<T>的是基于数组实现的可变长度的列表。
很多小伙伴发现,List<T>即有Count属性又有Count()方法,并且有人做过性能测试,Count属性比Count()方法更快,因此得出结论,Count属性是直接返回一个计算好的值,Count()方法需要遍历列表计算长度。
事实是怎样的?像微软这样全球顶级的开发团队,是否会在基础类库中提供两个一样的功能,我们来探究一下。
02
—
源码探究
Count属性是List<T>提供的只读属性,直接返回私有变量_size记录的元素数量。
Count()方法是System.Linq.Enumerable中提供的扩展方法,List<T>实现接口IList<T>,间接实现接口ICollection<T>,由源码可知,通过List<T>对象调用Count()方法,返回的是List<T>对象的Count属性,二者并没有区别。
Count()方法存在的意义是什么呢?
03
—
软件设计原则
微软设计原则,参数设计原则中有一条:
请使用提供成员所需功能的最低派生参数类型。
例如,假设你想要设计这样一种方法,它可枚举集合并将每个项目输出到控制台。 此类方法应将 IEnumerable 用作参数,而不是使用 ArrayList 或 IList 等内容。
微软文档:https://learn.microsoft.com/zh-cn/dotnet/standard/design-guidelines/parameter-design
微软设计原则建议,在满足所需功能的情况下,应使用IEnumerable,而不是使用ArrayList或IList,这也叫说明了Count()方法存在的意义,因为在IEnumerable中没有Count属性,只能通过Count()方法间接获取元素数量。
这里体现了面向对象开发原则(SOLID),使用最低派生类型,职责单一,其子类型(实现类)易于替换,代码可扩展性更好,符合开放封闭原则。
如何看待Count()方法比Count属性慢?
04
—
正确认识性能问题
客观的看待性能问题,应当从相对性能和绝对性能两方面进行交叉对比,从而得出一个中肯的结论。
Count()方法比Count属性,大概慢10ns(不同设备环境会有差异),也就是百万分之十毫秒,一亿分之一秒,绝对性能差异微乎其微,而大部分性能测试为了体现两者的性能差异,循环上百万次,再对两者进行对比,通过相对性能展示性能差异,殊不知,Count属性本身耗时极低,相对性能差异被夸大。
这一点一定要认识清楚,同样的有文章分析在List<T>集合中Exists()比Any()性能好,也是相同的原理,切不可被片面的言论左右。
软件开发过程就是一个决策取舍的过程,你是希望获得更高的性能,还是更好的扩展性,相信每个小伙伴心中都有自己的答案。
喜欢的朋友可以点赞,转发,加关注