1.使用as或is的优势:
如果无法进行转换,则 null 而非引发异常,只需要检查返回的引用是否为null即可,避免了异常处理带来的开销。
使用as操作符转换对象为null时返回null,如果使用强制转换的方式null可以被转换成任意的引用类型。
as操作符的限制:
as操作符不能配合值类型使用,因为它们永远都不可能为null。
is操作符的使用:
在不确定的强制类型转换中使用异常来控制程序流是一个很糟糕的做法,在转换之前我们可以使用is来避免冒出异常或转换。
当不能使用as进行转换时,才应该使用is操作符。否则is是多余的;因为使用as操作符只需要检查是否为null即可,这样更加简单。
2.使用Conditional特性:
[Conditional("DEBUG")]
private void CheckMethod(){}
Conditional特性的限制:
Conditional特性只可以应用在整个方法上。
任何使用了Conditional特性的方法都只能返回void类型。
3.装箱和取消装箱
System.Collections.ArrayList.如果必须频繁地将值类型装箱,则最好避免使用值类型,例如在非泛型集合类 如 [System.Collections.ArrayList]可以通过使用泛型集合(例如 [System.Collections.Generic.List<T>]来避免将值类型装箱。
装箱和拆箱都是需要大量运算的过程:
对值类型进行装箱时,必须创建一个全新的对象。此操作所需时间可比简单的引用赋值操作长 20 倍。
取消装箱时,强制转换过程所需时间可达赋值操作的四倍。
4.在连接大量字符串变量时,例如在紧凑循环中,请使用 [System.Text.StringBuilder] 而不是 C# [+ 运算符]或 Visual Basic 串联运算符
注:string.format 方法,其实最终是调用 StringBuilder
public static string Format(IFormatProvider provider, string format, params object[] args)
{
if ((format == null) || (args == null))
{
throw new ArgumentNullException((format == null) ? "format" : "args");
}
StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
builder.AppendFormat(provider, format, args);
return builder.ToString();
}
StringBuilder 是预先创建一个比较大的内存,以后每次操作时判断容量上限是否不够用,如果不够用就自动把容量扩大一倍,修改的还是第一次创建的对象的值。
结论:简单的拼接:用string.foramt
循环内拼写很长的字符串时,就需要用到StringBuilder来节省性能和内存了。
5.析构函数
不应使用空析构函数。如果类包含析构函数,Finalize 队列中则会创建一个项。
调用析构函数时,将调用垃圾回收器来处理该队列。 如果析构函数为空,只会导致性能降低
6.使用using和try/finally清理资源
在C#中为我们添加了一个现实释放非托管资源的关键字:using:
using语句其实是一个C#语言的语法糖,当我们在using语句中分配可释放对象时,C#编译器将会自动在每个对象外生成一个try/finally块来包裹住分配的对象,保证资源的及时释放,即使抛出了异常也一样。如果要使用一个可销毁的对象,使用using语句能够以最简单的方式保证你的对象可以正常销毁。
注意:如果using语句中分配的变量的类型没有实现IDisposable接口,编译器将会抛出异常。
安全销毁对象:
对于一些可能实现或未实现IDisposable接口的对象,或者无法确定是否应该用using语句包裹某个对象时,由于其不确定性我们可以使用as操作符进行安全的销毁
object obj = Factory.CreateResource();
//如果不确定obj是否实现了IDisposable接口,下面是安全的销毁方式
using (obj as IDisposable)
{
Console.WriteLine(obj.ToString());
}
如果obj实现了IDisposable接口,那么using语句将生成清理代码;反之,using语句将变成using(null) ,这并不会抛出异常,也不会有任何其他意料之外的操作。
必须保证每个实现了IDisposable接口的对象都放在了using或try/finally中,否则就可能会发生资源泄露。
释放可销毁对象的方式:
我们发现在我们释放可销毁对象时。有的类型不但提供Dispose()方法还提供了一个Close方法,比如前面示例中SqlConnection类的myConnection对象,我们可以知道调用myConnection对象的Close方法关闭数据库连接,但是这和调用它的Dispose()有一些差别:Dispose()方法将调用GC.SuppressFinalize()方法,而Close()方法一般则不会,因此,即使已经不需要终结,但对象仍旧在终结队列中。如果两种方式你可以选择,应该优先使用Dispose方法。
同时我们需要知道:Dispose()并不是将对象从内存中移除,而只是让对象释放掉其中的非托管资源。
7.避免创建非必要的对象
将常用的局部变量提升为成员变量:
所有的引用类型,包括那些局部变量,都会分配到堆上。在函数退出后,函数内的所有局部变量都会立即变成垃圾对象。所以我们可以得出结论:若是某个引用类型(值类型无所谓)的局部变量用于被频繁调用的例程中,那么应该将其提升为成员变量。这既有助于减轻GC的负担,也可以提升程序运行的效率。
为常用的类型实例提供静态对象:
静态成员变量可以让引用类型在类的各个实例中共享。我们可以通过提供了一个类,存放某个类型常用的实例的单例对象,这样可以避免创建重复的对象。
为不可变类型提供可变的创建方式:string.Format("{0},a}"