【IT168技术文档】
一、“短路”运算
在使用C#.NET的用户可能经常使用“短路”运算。例如&&、||运算符,
在该代码中如果i<0则不会判断j是否大于0,因为如果i<0无论j是否大于0返回的结果都是false;同理如果执行以下语句if (i>0 || j>0) Console.WriteLine("OK");如果i>0则不会判断j是否大于0,因为如果i>0无论j是否大于0返回的结果都是true。int i=-10;int j=17; if (i>0 && j>0) Console.WriteLine("OK");
但是在VB.NET中的And、Or不是“短路”运算符,And和Or都要计算运算符两侧的结果,这样会有不必要的运算。但在VB.NET中要实现“短路”运算,可以通过AndAlso、OrElse实现。AndAlso等同于&&,OrElse等同于||。
二、不使用Public字段,使用属性
在设计类的过程中是用Public字段可以被其他成员访问,但该字段的安全性和封装性很差。推荐使用属性来代替Public字段。对属性使用前必须实例化拥有该属性的类,属性是特殊的方法在属性体里可以编写代码,这些都是Public字段无法拥有的好处。
三、早期绑定和后期绑定
Dim s As String属于早期绑定;Dim s : s = "String"属于后期绑定。后期绑定给开发人员带来了方便,但在运行时需要使用反射并查询对象的类型和方法,还要在不同类型的对象之间进行转换。这些都给性能带来了损失。使用早期绑定,编译器知道使用的对象引用的类型,运行时不需要使用反射,性能较后期绑定有了很大的提高。
Option Strict选项开关可以让用户决定是否允许使用后期绑定,就本人的观点而言后期绑定和反射技术在.NET里面功能相当强大,灵活使用反射技术可以创造出功能强大而代码相当精简的软件。建议读者在每个页面上通过<%@ Page Strict=”true”%>或<%@ Control Strict=”true”%>来关闭后期绑定的使用,不要在全局上关闭后期绑定和反射。
四、数组的数组(锯齿数组)
锯齿数组在使用上是否恰当对性能是有些影响的。例如:创建一个二维数组用来存放一年的每一天,可以这样声明数组:Dim ymd(12,31) As Integer。在这个二维数组中:行代表月份,列代表日。这个数组共有372个元素。但全年的天数是365天或366天,比二维数组定义的372个元素要少。可以用锯齿数组存放一年的每一天。锯齿数组的定义如下:Dim ymd(12)() As Integer。从该定义可以看出,ymd共有12个元素但每个元素都是Integer类型的数组,并且维数不定。维数是根据当月的实际天数来确定:ymd(i) = New Integer(DateTime.DaysInMonth(DateTime.Now.Year, i)) {}。这样锯齿数组在内存消耗上比二维数组要少,在以后使用过程中对数据的检索比二维数组要快。感兴趣的读者自行试验。
五、弱引用
把一个对象引用分配给一个变量时,该变量就包含对对象的一个强引用。GC不会收回强引用任在使用的对象。只有当变量离开作用域时,或是显式的给变量分配Nothing时,强引用才被删除。
弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存。对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必要时回收时,可以考虑使用弱引用。弱引用的用法如下:
Dim strLarge As New String("b"c, 4096) '声明一个名为strLarge,长度为4096的变量 Dim weakRef As New WeakReference(strLarge)'声明一个弱引用的变量,把strLarge存放在里面 Application("weakRef") = weakRef '把弱引用对象存放在Application中 Dim weakTarget As WeakReference '声明一个弱引用的变量 If Not Application("weakRef") Is Nothing Then '判断Application中是否存在strLarge weakTarget = CType(Application("weakRef"), WeakReference) 'Application中存放的strLarge对象转换成弱引用,交给weakTarget处理 Dim targetStr As String = CType(weakTarget.Target, String) '获取弱引用中的值 If targetStr Is Nothing Then '如果targetStr的值为空,说明对象被GC回收了 End If End If
六、装箱和拆箱
在.NET中数据类型主要分成两类:值类型和引用类型。编译器把值类型放在堆栈中,对值类型的访问时直接的。引用类型派生自Object类,运行时在堆上为引用类型分配存储空间。总是通过引用访问这个存储空间,GC跟踪这个存储空间,在将来进行收集。
值类型和引用类型的互相转换,在.NET中称为“装箱”和“拆箱”。装箱创建一个新的对象并把值类型的为复制到托管堆中,然后返回对新的存储位置的一个引用。这是一个隐式的操作,相对比较消耗资源。拆箱是把一个引用类型转换成值类型。
“装箱”和“拆箱”在项目开发过程中是非常常见的。在状态管理中已经频繁使用了“装箱”和“拆箱”。例如:
其中iLoginUserNum是个整形变量,用来存放当前登录的用户数。Application中存放的是Object,要把iLoginUserNum存放到Application中,需要将iLoginUserNum从整形转换成Object。这个过程称为“装箱”。iLoginUserNum=CType(Application(“iLoginUserNum”),Integer)+1是把Application中的iLoginUserNum值加1。在这个语句中需要把Application(“iLoginUserNum”)转换成整形,这个过程称为“拆箱”。Dim iLoginUserNum As Integer=16 Application(“iLoginUserNum”)= iLoginUserNum
要减少“装箱”、“拆箱”带来的性能损失,可以设法避免“装箱”,避免“装箱”可以提高50%的性能。具体方法如下:
在Application(“iLoginUserNum”)= iLoginUserNum中iLoginUserNum是个值类型。如果是个引用类型,把引用类型放在Application中就可以避免“装箱”了。构架LoginUserNum类:
Public Class LoginUserNum Private _LoginUserNum As Integer Public Sub New(ByVal value As Integer) _LoginUserNum = value End Sub Public Property Value() As Integer Get Value = _LoginUserNum End Get Set(ByVal Value As Integer) _LoginUserNum = Value End Set End Property End Class //把Dim iLoginUserNum As Integer=16:Application(“iLoginUserNum”)= iLoginUserNum改成: Dim iLoginUserNum As New LoginUserNum(16) Application(“iLoginUserNum”)= iLoginUserNum