技巧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型字段来说,能大大节省内存。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?