z1.在适当的情况下对对象实现弱引用。
为对象实现弱引用,是有效提高性能的手段之一。弱引用是对象引用的一种“中间态”,实现了对象既可以通过GC回收其内存,又可被应用程序访问的机制。这种看似矛盾的解释,的确对胖对象的内存性能带来提升,因为胖对象需要大量的内存来创建,弱引用机制保证了胖对象在内存不足时GC可以回收,而不影响内存使用,在没有被GC回收前又可以再次引用该对象,从而达到空间与时间的双重节约。
在.NET中,WeakReference类用于表示弱引用,通过其Target属性来表示要追踪的对象,通过其值赋给变量来创建目标对象的强引用


2 {
3 public class Class1
4 {
5 public static void Main()
6 {
7 MyClass mc = new MyClass();
8 //创建弱类型对象
9 WeakReference wr = new WeakReference(mc);
10 //移除强类型
11 mc = null;
12 if (wr.IsAlive)
13 {
14 //弱引用转换为强引用, 对象可以再次使用。
15 mc = wr.Target as MyClass;
16 mc.getName();
17 }
18 else
19 {
20 //对象已经被回收,重新使用。
21 mc = new MyClass();
22 }
23 }
24 }
25
26 public class MyClass
27 {
28 public void getName()
29 {
30 Console.WriteLine("dao");
31 }
32 }
33
34
35 }
2.尽可能以using来执行资源清理。
以using语句来执行实现了Dispose模式的对象,是较好的资源清理选择,简洁优雅的代码实现,同时能够保证自动执行Dispose方法来销毁非托管资源。
3.推荐使用泛型集合来代替非泛型集合。
泛型实现了一种类型安全的算法重用,其最直接的应用正是在集合类中的性能与安全的良好体现,因此我们建议以泛型集合来代替非泛型集合,以List<T>和ArrayList为例来做以说明:


2 {
3 Stopwatch watch = new Stopwatch();
4 //List<T>性能测试
5 List<Int32> list = new List<Int32>();
6 watch.Start(); //开始计时
7 for (Int32 i = 0; i < 10000000; i++)
8 {
9 list.Add(i);
10 }
11 watch.Stop(); //计时结束
12 Console.WriteLine(watch.ElapsedMilliseconds);
13 //未发生装箱
14
15 //ArrayList性能测试
16 ArrayList al = new ArrayList();
17 watch.Restart();//重新计时。
18 for (Int32 j = 0; j < 10000000; j++)
19 {
20 //发生装箱
21 al.Add(j);
22 }
23 watch.Stop(); //计时结束
24 Console.WriteLine(watch.ElapsedMilliseconds);
25 }
上述示例,仅仅给出了泛型集合和非泛型集合在装箱操作上引起的差别,同样的拆箱操作也伴随了这两种不同集合的取值操作。同时,大量的装箱操作会带来频繁的垃圾回收,类型转换时的安全检查,都不同程度的影响着性能,而这些弊端在泛型集合中荡然无存。
注意,这种性能差别对值类型的影响较大,而引用类型不存在装箱与拆箱问题,因此性能影响不是很明显。
4.初始化时最好为集合对象指定大小
长度动态增加的集合类,例如ArrayList、Queue的等。可以无需指定其容量,集合本身能够根据需求自动增加集合大小,为程序设计带来方便。然而,过分依赖这种特性并非好的选择,因为集合动态增加的过程是一个内存重新分配和集合元素复制的过程,对性能造成一定的影响,所以有必要在集合初始化时指定一个适当的容量。例如:


2 {
3 ArrayList al = new ArrayList(2);
4 al.Add("One");
5 al.Add("Two");
6 //容量动态增加一倍
7 al.Add("Three");
8 Console.WriteLine(al.Capacity);
9 }
5.特定类型的Array性能优于ArrayList
ArrayList只接受Object类型的元素,向ArrayList添加其他值类型元素会发生装箱与拆箱操作,因此在性能上使用Array更具优势,当然object类型的数组除外。不过,ArrayList更容易操作和使用,所以这种选择同样存在权衡与比较。
6.合理使用System.String和System.Text.StringBuilder
在简单的字符串操作中使用String,在复杂的字符串操作中使用StringBuilder。简单地说,StringBuilder对象的创建代价较大,在字符串连接目标较少的情况下,应优先使用String类型;而在有大量字符串连接操作的情况下,应优先考虑StringBuilder。 同时,StringBuilder在使用上,最好指定合适的容量值,否则由于默认容量的不足而频繁进行内存分配的操作会影响系统性能。
7.尽量在子类中重写ToString方法
ToString方法是System.Object提供的一个公有的虚方法,.NET中任何类型都可继承System.Object类型提供的实现方法,默认为返回类型全路径名称。在自定义类或结构中重写ToString方法,除了可以有效控制输出结果,还能在一定程度上减少装箱操作的发生。
8.字符串比较
字符串比较,常常习惯的做法是:
public bool StringCompare(string str1, string str2)
{ return str1 == str2; }
而较好的实现应该是:
public int StringCompare(string str1, string str2)
{ return String.Compare(str1, str2); }
二者的差别是:前者调用String.Equals方法操作,而后者调用String. Compare方法来实现。String.Equals方法实质是在内部调用一个EqualsHelper辅助方法来实施比较,内部处理相对复杂。因此,建议使用String.Compare方式进行比较,尤其是非大小写敏感字符串的比较,在性能上更加有效。
类似的操作包含字符串判空的操作,推荐的用法以Length属性来判断,
当然了这种情况只能用于判断 string aa="", 不能判断 string aa=null。
例如: public bool IsEmpty(string str)
{ return str.Length == 0; }
9.for和foreach的选择。
推荐选择foreach来处理可枚举集合的循环结构,原因如下:
1 .NET 2.0以后编译器对foreach进行了很大程度的改善,在性能上foreach和for实际差别不大。
2. foreach语句能够迭代多维数组,能够自动检测数组的上下限。
3. foreach语句能够自动适应不同的类型转换。
4. foreach语句代码更简洁、优雅,可读性更强。


2 {
3 ArrayList al = new ArrayList(3);
4 al.Add(100);
5 al.Add("Hello, world.");
6 al.Add(new char[] { 'A', 'B', 'C' });
7
8 foreach (object o in al)
9 Console.WriteLine(o.ToString());
10
11 for (Int32 i = 0; i < al.Count; i++)
12 Console.WriteLine(al[i].ToString());
13 }
10.尽可能少地抛出异常,禁止将异常处理放在循环内。
异常的发生必然造成系统流程的中断,同时过多的异常处理也会对性能造成影响,应该尽量用逻辑流程控制来代替异常处理。对于例行发生的事件,可以通过编程检查方式来判断其情况,而不是一并交给异常处理,
例如: Console.WriteLine(obj == null ? String.Empty : obj.ToString());
不仅简洁,而且性能表现更好,优于以异常方式的处理:
try
{
Console.WriteLine(obj.ToString());
}
catch (NullReferenceException ex)
{
Console.WriteLine(ex.Message);
}
当然,大部分情况下以异常机制来解决异常信息是值得肯定的,能够保证系统安全稳定的面对不可意料的错误问题。例如不可预计的溢出操作、索引越界、访问已关闭资源等操作,则应以异常机制来处理。
11.以is/as模式进行类型兼容性检查。
以is和as操作符可以用于判断对象类型的兼容性,以is来实现类型判断,以as实现安全的类型转换,是值得推荐的方法。这样能够避免不必要的异常抛出,从而实现一种安全、灵活的转换控制


2 {
3 MyClass mc = new MyClass();
4 if (mc is MyClass)
5 {
6 Console.WriteLine("mc is a MyClass object.");
7 }
8 object o = new object();
9 MyClass mc2 = o as MyClass;
10 if (mc2 != null)
11 { //对转换类型对象执行操作 }
12 }
13 }
12.const和static readonly的权衡。
const是编译时常量,readonly是运行时常量,所以const高效,readonly灵活。在实际的应用中,推荐以static readonly来代替const,以解决const可能引起的程序集引用不一致问题,还有带来的较多灵活性控制。
13.尽量避免不当的装箱和拆箱,选择合适的代替方案。
通过本节多个条款的性能讨论,我们不难发现很多情况下影响性能的正是装箱和拆箱,例如非泛型集合操作,类型转换等,因此选择合适的替代方案是很有必要的。可以使用泛型集合来代替非泛型集合,可以实现多个重载方法以接受不同类型的参数来减少装箱,可以在子类中重写ToString方法来避免装箱等等。
14.以FxCop工具,检查你的代码。
FxCop是微软开发的一个针对.NET托管环境的代码分析工具,可以帮助我们检查分析现存托管程序在设计、本地化、命名规范、性能和安全性几个方面是否规范。
尤其是在性能的检查方面,FxCop能给我们很多有益的启示,最重要的是FxCop简单易用,而且免费,在改善软件质量,重构既有代码时,FxCop是个不错的选择工具。