编写高质量代码改善C#程序的157个建议——建议20:使用泛型集合代替非泛型集合
建议20:使用泛型集合代替非泛型集合
在建议1中我们知道,如果要让代码高效运行,应该尽量避免装箱和拆箱,以及尽量减少转型。很遗憾,在微软提供给我们的第一代集合类型中没有做到这一点,下面我们看ArrayList这个类的使用情况:
ArrayList al=new ArrayList();
al.Add();
al.Add();
al.Add("mike");
foreach (var item in al)
{
Console.WriteLine(item);
}
上面这段代码充分演示了我们可以将程序写得多么糟糕。首先,ArrayList的Add方法接受一个object参数,所以al.Add(1)首先会完成一次装箱;其次,在foreach循环中,待遍历到它时,又将完成一次拆箱。在这段代码中,整形和字符串作为值类型和引用类型,都会先被隐式地强制转型为object,然后在foreach循环中又被转型回来。同时,这段代码也是非类型安全的:我们然ArrayList同时存储了整型和字符串,但是缺少编译时的类型检查。虽然有时候需要有意这样去实现,但是更多的时候,应该尽量避免。缺少类型检查,在运行时会带来隐含的Bug。集合类ArrayList如果进行如下所示的运算,就会抛出一个IvalidCastException:
ArrayList al=new ArrayList();
al.Add();
al.Add();
al.Add("mike");
int t = ;
foreach (int item in al)
{
t += item;
}
ArrayList同时还提供了一个带ICollection参数的构造方法,可以直接接收数组,如下所示:
var intArr = new int[] {, , , };
ArrayList al=new ArrayList(intArr);
该方法内部实现一样糟糕,如下所示(构造方法内部最终调用了下面的InsertRange方法):
public virtual void InsertRange(int index, ICollection c)
{
if (c == null)
{
throw new ArgumentNullException("c", Environment.GetResourceString("ArgumentNull_Collection"));
}
if ((index < ) || (index > this._size))
{
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
int count = c.Count;
if (count > )
{
this.EnsureCapacity(this._size + count);
if (index < this._size)
{
Array.Copy(this._items, index, this._items, index + count, this._size - index);
}
object[] array = new object[count];
c.CopyTo(array, );
array.CopyTo(this._items, index);
this._size += count;
this._version++;
}
}
概括来讲,如果对大型集合进行循环访问、转型或装箱和拆箱操作,使用ArrayList这样的传统集合对效率影响会非常大。鉴于此,微软提供了对泛型的支持。泛型使用一对<>括号将实际类型括起来,然后编译器和运行时会完成剩余的工作。微软也不建议大家使用ArrayList这样的类型了,转而建议使用它们的泛型实现,如List<T>。
注意,非泛型集合在System.Collections命名空间下,对应的泛型集合则在System.Collections.Generic命名空间下。
建议一开始的那段代码的泛型实现为:
List<int> intList = new List<int>();
intList.Add();
intList.Add();
//intList.Add("mike");
foreach (var item in intList)
{
Console.WriteLine(item);
}
代码中被注释的那一行不会被编译通过,因为“mike"不是整型,这里就体现了类型安全的特点。
下面比较了非泛型集合和泛型集合在运行中的效率:
static void Main(string[] args)
{
Console.WriteLine("开始测试ArrayList:");
TestBegin();
TestArrayList();
TestEnd();
Console.WriteLine("开始测试List<T>:");
TestBegin();
TestGenericList();
TestEnd();
}
static int collectionCount = ;
static Stopwatch watch = null;
static int testCount = ;
static void TestBegin()
{
GC.Collect(); //强制对所有代码进行即时垃圾回收
GC.WaitForPendingFinalizers(); //挂起线程,执行终结器队列中的终结器(即析构方法)
GC.Collect(); //再次对所有代码进行垃圾回收,主要包括从终结器队列中出来的对象
collectionCount = GC.CollectionCount(); //返回在0代码中执行的垃圾回收次数
watch = new Stopwatch();
watch.Start();
} static void TestEnd()
{
watch.Stop();
Console.WriteLine("耗时:" + watch.ElapsedMilliseconds.ToString());
Console.WriteLine("垃圾回收次数:" + (GC.CollectionCount() - collectionCount));
} static void TestArrayList()
{
ArrayList al = new ArrayList();
int temp = ;
for (int i = ; i < testCount; i++)
{
al.Add(i);
temp = (int)al[i];
}
al = null;
} static void TestGenericList()
{
List<int> listT = new List<int>();
int temp = ;
for (int i = ; i < testCount; i++)
{
listT.Add(i);
temp = listT[i];
}
listT = null;
}
输出为:
开始测试ArrayList:
耗时:2375
垃圾回收次数:26
开始测试List<T>:
耗时:220
垃圾回收次数:5
转自:《编写高质量代码改善C#程序的157个建议》陆敏技
编写高质量代码改善C#程序的157个建议——建议20:使用泛型集合代替非泛型集合的更多相关文章
- 编写高质量代码改善C#程序的157个建议[1-3]
原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...
- 读书--编写高质量代码 改善C#程序的157个建议
最近读了陆敏技写的一本书<<编写高质量代码 改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...
- 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试
建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...
- 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本
建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...
- 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码
建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...
- 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣
建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...
- 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释
建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...
- 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释
建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...
- 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量
建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...
- 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法
建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...
随机推荐
- javabrideg的使用实践
(1)进入这个网站http://sourceforge.net/projects/php-java-bridge/files,选择Binary package,然后选择最新的版本Php-java-br ...
- JBPM的ORACLE脚本
create table JBPM4_DEPLOYMENT ( DBID_ number(19,0) not null, NAME_ clob, TIMESTAMP_ number(19,0), ST ...
- EditText动态转换只读/编辑状态
public class MyActivity extends Activity { private KeyListener listener; private EditText editText; ...
- .Net上传文件超过了最大请求长度
错误消息:超过了最大请求长度 错误原因:asp.net默认最大上传文件大小为4M,运行超时时间为90S. 修改web.config文件可以改变这个默认值为 <configuration&g ...
- An internal error occurred during: "Map/Reducelocation status updater".java.lang.NullPointerException
当我们运行wordcount代码时,出现报错,如下所示: An internal error occurred during: "Map/Reducelocation status upda ...
- mysql锁,事务
什么是事务 事务定义了一个服务操作序列,由服务器保证这些操作序列在多个客户并发访问和服务器出现故障情况下的原子性事务的属性 A --redo&undo C --undo I --lock D ...
- spring mvc helloworld 和表单功能、页面重定向
Spring MVC Hello World 例子 这里有个很好的教程:https://www.cnblogs.com/wormday/p/8435617.html 下面的例子说明了如何使用 Spri ...
- Python 正则表达式之选择
In [4]: import re In [5]: re.findall(r"\d+","jjj1234mm222")Out[5]: ['1234', '222 ...
- leetcode539
public class Solution { public int FindMinDifference(IList<string> timePoints) { * ]; foreach ...
- 华为部分真机调试无法显示log问题解决
真机测试时,部分华为手机无法获取全部的log信息.或者说无法获取Error以下级别的log信息.比如P7 这是因为部分华为机出厂默认log设置为关闭状态,因此只能获取Error以上级别的log信息.蛋 ...