技巧1.使用EventHanlderList代替EventHandler
以Control的Init事件为例。通常我们会简单的用一个语句来定义事件:
然而我们看实际的代码却是:
public event EventHandler Init
{
add
{
this.Events.AddHandler(EventInit, value);
}
remove
{
this.Events.RemoveHandler(EventInit, value);
}
}
Events属性就是EventHandlerList类型的对象。
这样做的原因有两个:
1.第一种写法不管该事件有没有响应函数,都会创建一个相应的代理对象。假如一个类中有20个事件,将创建20个代理对象,而这20个代理对象有可能都用不上。
2.第一种写法编译器将为每一个事件生成Add与Remove方法,这两个方法是线程安全的,因此它包含了一些线程同步的代码。对于根本不需要使用多线程的程序来说,这对性能也是一种损耗。
技巧2.使用静态object代替string类型作为字典主键
在上面的例子中,我们还发现另一个跟我们平常不一样的用法,就是this.Events.AddHandler(EventInit, value);语句中的EventInit属性。我们先看定义
它一个简单的object,在这里做主键来使用。我们一般使用字典的时候都习惯用字符串类型作为主键,因此我们会写成this.Events.AddHandler(“EventInit”, value);
这样写会有两个缺点,第一字符串占内存多,第二容易出错。对于容易出错这一点,有必要展开讲。
首先,字符串内容不会被编译器检查,非常容易写错,不仅仅是大小写的问题,即使我们把I写成L,编译器也能通过,而有时肉眼很难分辨。当然我们可以定义成常量,但是又回到内存占用的问题上了。
第二,字符串是一个特殊的类,它的特性其实很多人不是特别了解。比如字符串的驻留,字符串的比较,字符串的哈希。如果集合类把字符串当做一般对象处理,就会出现问题。
如果我们使用静态object字段作为主键,则上述两个问题都不会存在。每个对象在内存中的地址都是唯一的,因此用来做主键是非常合适的。
(ViewState使用string作为主键应该是考虑到序列化的问题)
技巧3.使用BitVector代替bool类型字段
在程序中我们经常使用bool类型的字段作为标志,比如Page是否支持视图状态,我们可以定义
这样,编译器会自动生成一个bool型的字段。然而我们看实际的源代码:
{
get
{
return !this.flags[disableViewState];
}
set
{
this.SetEnableViewStateInternal(value);
}
}
private const int disableViewState = 4;
关键在于flags对象。该对象是一个SimpleBitVector32类型。使用字典的方式存取标志位,一个SimpleBitVector32对象能保存32个标志位。相当于32个bool型字段。它内部其实也只存了一个int型的字段,但是它使用每一个位作为标志。这样相对于使用bool型字段来说,能大大节省内存。