一个简单的HLSL程序,返回一个材质的各点的颜色。

sampler s0 : register(s0);

float4 main(float2 tex : TEXCOORD0) : COLOR

{

     return tex2D(s0,tex);

}

HLSL,颜色表示。

        使用MPC的custom shader,由于在MPC中需要使用HLSL编写shader,所以首先要了解HLSL里面的颜色表示法,HLSL中,尤其是MPC中,颜色基本都是使用XRGB表示(X代表保留位),一般将其表示为一个四维矢量,数据类型是float4。比如float4 color;,那么接下来就可以用color.x,color.y,color.z,来分别访问R,G,B三个分量了。

        众所周知,对于24位,或者32位图像来说来说,RGB每个通道都是8位,转化为10进制就是0-255的整数,不过在HLSL中情况不同,0对应的是float(0.0)而255对应的是float(1.0),所以白色表示不再是(255,255,255)而是float3(1.0,1.0,1.0)或者float4(1.0,1.0,1.0,1.0)。

程序解释

        第一行定义了一个sampler,将pixel shader寄存器s0与我们定义的sampler s0绑定,在MPC中,寄存器s0就是影片图像所对应的纹理。

       float4 main(float2 tex : TEXCOORD0) : COLOR,它代表的意思是,输出一个float4变量,将这个float4变量作为COLOR(作为render target 0中的颜色,关于render target,后面会解释)。这个函数有一个输入参数,就是作为0号纹理坐标(TEXCOORD0)的float2类型的tex。

       HLSL中的最简单的2D纹理映射函数是tex2D(s,t);两个参数,第一个是一个sampler,它代表的是目标纹理和纹理过滤,寻址方式,第二个参数是一个float2,也就是纹理坐标uv。它返回一个颜色值float4,这就是:纹理s中,纹理坐标t处的颜色之意。

      在这里就需要说明作为输入的TEXCOORD0的内容了,在MPC中,我们知道原纹理要经过shader处理后写入一个新的同样大小的纹理中,所以事实上它绘制了一个full rect quad(全区域矩形)并把新的纹理作为该次绘制的输出对象(即绘制的东西就不显示于屏幕上,而绘制到该纹理中)。

练习下看代码:

      变亮20%

sampler s0 : register(s0);

float4 main(float2 tex : TEXCOORD0) : COLOR

{

float4 color0 = tex2D(s0,tex);

return color0+color0*float4(0.2,0.2,0.2,0.0);

}

常用MUL函数

    上面color0*float4(0.2,0.2,0.2,0.0)是对位相乘。即:

    color1 = color0*scale;

    则代表

    color1.x = color0.x*scale.x;

    color1.y = color0.y*scale.y;

    color1.z = color0.z*scale.z;

    color1.w = color0.w*scale.w;

    如果需要得到矢量点积,需要用mul(x,y);

    比如float lum = mul(color0.xyz,float3(0.3,0.59,0.11) );其中color0.xyz表示以color0的xyz元素构成的一个3维向量,lum = color0.x*0.3 + color0.y*0.59 + color0.z*0.11;

读代码练习:

灰度转换shader

sampler s0 : register(s0);

float4 main(float2 tex : TEXCOORD0) : COLOR

{

    float4 color0 = tex2D(s0,tex);

    float lum = mul(color0.xyz,float3(0.3,0.59,0.11) );

    return float4(lum,lum,lum,1.0);

}

HLSL的PS版本的问题

     会用color0+color0*float4(0.2,0.2,0.2,0.0)而不是color0*float4(1.2,1.2,1.2,1.0)是由于ps版本问题。版本越高,HLSL就越灵活,当然,硬件功能要求也就越强。对于ps1.x来说,常量寄存器不能储存超过1的数值,所以如果用float4(1.2,1.2,1.2,1.0)运行时会直接当作float4(1.0,1.0,1.0,1.0)处理,也可以说,是HLSL编译器比较弱智,不能自动转化为color0+color0*float4(0.2,0.2,0.2,0.0)。

     (所以会看到wow为每个ps版本写了不同的代码。)

如何获得相邻像素

       如下图,设原纹理大小为M*N个texel,于是每个texel的uv尺寸为(1.0/M,1.0/N),所以可以通过将tex偏移再tex2D来取得相邻处的texel。

       

 

GPU汇编指令

       add——vec1+vec2——矢量对位相加

       mul——vec1*vec2——矢量对位相乘

      mad——vec1*vec2+vec3——矢量对位乘加

       dp3——vec1.x*vec2.x+vec1.y*vec2.y+vec1.z*vec2.z——矢量点积

       等运算,而标量单元负责的是诸如

       pow——scar1^scar2——标量幂运算

       rcp——1.0/scar1——标量倒数运算

       rsq——1.0/sqrt(scar1)——标量方根倒数

       log——log2(scar1)——2为底的对数

       等等

      而纹理单元,执行的自然是

       texld——纹理采样函数

    

在MPC的HLSL编译目标(compile target)选项中,有意义的包括ps_1_1,ps_1_3,ps_1_4,ps_2_0,ps_3_0。HLSL code的结构复杂度、指令的复杂性、指令数多寡决定了它最低需要的编译目标。

ps_1_1和ps_1_3在实际应用中差别甚微。都属于限制非常大的编译目标,主要限制是:

1:最大指令数目限制严重,不能超过8条算术指令(尽管其实可以不超过3维的矢量运算与标量运算并发(co-issue)所以最多是16条算术指令,但是不用指望HLSL编译器能够强大到如此程度)和4条纹理指令(ps1.1-1.3的纹理指令其实比较复杂,属于组合功能方式,但是在MPC中基本用不上)

2:无复杂运算指令,诸如rcp,rsq,log,pow等全部没有

3:寄存器数值范围很窄,比如float s1 = 1.5 * s2;就会自动变成float s1 = 1.0 * s2;(也就是1.5超出了范围),只能写成float s1 = s2+0.5*s2;才能正确编译

4:无dependent texture read。而tex基本可以认为无法操作

5:分支什么的就基本不用指望了。除了像if(s1>0.0){s2 = 1.0;}else{s2 = 0.0;}这种极其简单的。

ps_1_1级别的硬件,比较流行的是Nvidia Geforce 3

ps_1_3级别的硬件,比较流行的是Nvidia Geforce 4Ti

ps_1_4比ps_1_3适应性广一些包括

1:最大指令数限制有所松动,算术指令翻倍,纹理指令翻2倍。

2:支持一定限度的dependent texture read(1级),tex可以进行一定程度的操作

ps_1_4级别的硬件,比较流行的是ATI Radeon8500,9000-9200

事实上,由于ps1.x属于定点数结构,所以有一些移位指令可以使用,比如mul_x2,add_x2代表将结果相加后左移一位,相当于乘二。这也是为何第六节的第四个程序有ps1.x版本的原因。不过说到底,ps1.x不是为HLSL准备的。

ps_2_0是HLSL诞生时的默认编译对象

1:支持绝大多数的HLSL函数。

2:64条算术指令,32条纹理指令,最多4级的dependent texture read

3:全部浮点流水线,数据范围精度增强。

4:尽管ps_2_0没有硬件支持的动态分支,不过可以实现一定程度的分支,只不过每个分支都要跑一遍。也就是效率不会很高

ps_2_0级别的硬件包括Nvidia GeforceFx系列(ps_2_a)ATI Radeon 9500及以上X700以下(ps_2_0)X700,X800,X850系列(ps_2_b)

ps_3_0是当前PC上的最高pixel shader版本

1:比ps_2_0增加了一些指令

2:硬件支持分支,循环

3:最大指令数大大增加,不再有纹理算术指令数量分配的限制

4:dependent texture read级数没有限制

ps_3_0级别硬件包括Nvidia Geforce 6系列,7系列,ATI Radeon X1xxx系列

所以,编写HLSL请考虑自身硬件的功能等级。

以下是一些简单的提升性能的考虑

1:如果可以,使用ps1.x编译对象能获得最佳性能,如果该HLSL code不能使用ps1.x编译对象,那么请使用可用的最高ps版本的编译对象,如Geforce6系列就请使用ps_3_0编译对象。

2:在许可的情况下尽量减少使用复杂运算指令,诸如pow,sin,cos,asin,acos,sqrt等。

3:对于Nvidia Geforce Fx和6系列,推荐将float(FP32)替换为half(FP16)以提高性能。

4:对于向量来说,选择需要的最小维数,比如能用float3(half3)就不要用float4(half4),能用标量就不要用矢量

5:动态分支不要太多,除非你用的是X1800XT……

posted @ 2009-04-17 21:52 我的地盘我做主 阅读(1064) 评论(0) 编辑

本篇文章是我对.net中非托管资源清理的一些见解,共享给大家,希望能够给初学者提供一些借鉴的地方.

.net中非托管资源如何清理

 

背景

这两天帮助其它项目组Review代码,发现有些地方实现了IDispose接口,同时也发现了一些关于IDispose的问题:

1.       A类型实现了IDispose接口,B类型里面含有A类型的字段,B类型没有实现IDispose接口

2.       一个类里面实现了Finalize终结器,同时也实现了IDispose接口,但在Dispose方法里面没有调用GC.SuppressFinalize(this)方法.

 

下面我对以上两个问题分别分析一下,并提出解决方案.

问题1:如果A类型里面有非托管资源需要在实现的IDispose接口里面释放,由于B类型没有实现IDispose接口,B类型的使用者要想释放A类型的非托管资源并不方便.这样的话,就有可能忘记了释放A类型的非托管资源.

解决方案:

实现B类型的IDispose接口,Dispose方法里面调用A类型的Dispose方法.这样,B类型的使用者在调用B类型Dispose的同时,就把A类型的Dispose也调用了.

 

问题2:Dispose方法里面没有调用GC.SuppressFinalize(this)方法,会有什么问题呢,这样会导致垃圾回收器不能对这个类型的对象及时回收. GC开始工作的时候,它首先将没有终结器的垃圾对象从内存中移除,有终结器的所有对象则添加到一个垃圾队列当中。GC会调用一个新线程来执行这些对象的终结器。当终结器执行完毕后,这个对象会从队列中被移除。这个对象在队列中移除之后,GC再次开始工作的时候,这个对象才能够被回收,所以有终结器的对象会比没有的在内存中保留更长的时间。在后面我会对这里再详细的描述一下.

解决方案:

Dispose方法中调用GC.SuppressFinalize(this)方法.这样的话,就不会把有终结器的对象则添加到垃圾队列当中.

 

切入正题

.net,非托管代码清理有两种方式:Finalize方式和Dispose方式.

Finalize方式:通过对自定义类型实现一个Finalize方法来释放非通过资源.

.net2.0开始,C#编译器不能对Finalize进行显示的调用和重写,必须使用析构函数来实现它.

Code

上面的代码就是通过Finalize方式来释放资源的跟C++用析构函数释放资源的代码很象.

但是它实现方式和C++不同,因为它是由垃圾回收器来管理内存的.

大家看到了,Finalize方式释放非托管资源很简单,但是如果你了解了他的实现方式,你可能就不会选择用它来释放非托管资源.

Finalize方式在.net内部是如何实现的呢?

GC(垃圾回收器)开始工作的时候,它首先将没有终结器的垃圾对象从内存中移除,有终结器的所有对象则添加到一个终止化队列当中。GC会调用一个新线程来执行这些对象的终结器。当终结器执行完毕后,这些对象会从队列中被移除。这时候由于这些对象在第一次检测到的时候没有被释放,它们将会进入第1代对象,直到GC检测到第0代对象和第1代对象再次充满时,这时候GC才会把刚才那些对象释放掉,所以有终结器的对象会比没有的在内存中保留更长的时间。

 

提示:垃圾回收器把托管堆中的对象分为3,分别是0,1,2.一般分配为:0代约256K,1代约是2MB,2代约是MB,代龄越高,容量就越大,显然效率也就越低.首先被添加到托管堆中的对象被定为第0,当第0代充满时,就会执行垃圾回收,未被回收的对象代领将提升1.

 

由于以上原因应该避免仅使用Finalize方式释放非托管资源.

 

Dispose模式:在自定义类中实现IDispose接口,在接口中的Dispose方法中对非托管资源进行释放.闲话少说,上代码

Code

上面的代码就是用Dispose方式释放资源的方法.因为上面自定义的Dispose(bool isDisposing)方法是virtual,所以还可以在派生类里面对它进行override

Code

这样可以确保释放继承链上所有对象的引用资源,在整个继承层次中传播Dispose模式.

 

思考

那用Dispose方式非托管资源就是最好的方法了吗?

其实不然,因为类型实现了IDispose接口,这个类的使用者必须显示调用Dispose方法,或者在创建该类型对象的时候使用using关键字,对于一些粗心的使用者可能会忘记调用Dispose方法,或者没有使用using关键字,这样就导致了非托管资源没有释放的后果.

 

最佳方案

 

同时实现终结器和Dispose方式.这样对于细心的使用者直接显示调用Dispose方法会提高垃圾回收的性能,对于粗心的使用者虽然忘记了调用Dispose方法,但也不至于使得非托管资源得不到释放.

注意这里用到了GC. SuppressFinalize(this)方法.

代码如下:

Code

posted @ 2009-02-24 16:00 我的地盘我做主 阅读(1531) 评论(13) 编辑

本文转载自《冰戈--真诚的平凡》, 感谢冰戈--真诚的平凡的分享。

一、 Design(设计)
1. Abstract types should not have constructors
抽象类不应该声明构造方法

2. Assemblies should have valid strong names
程序集应该具有强名称

3. Avoid empty interfaces
避免使用空的接口

4. Avoid excessive parameters on generic types
避免在泛型类中使用过多的类型参数

5. Avoid namespaces with few types
避免让名字空间含有过少的类型

6. Avoid out parameters
避免使用 out类型的参数

7. Collections should implement generic interface
集合类应该实现泛型接口

8. Consider passing base types as parameters
尽量使用基本类型作为参数

9. Declare event handlers correctly
正确的声明事件处理器,事件处理器不应该具有返回值

10. Declare types in namespaces
应该在名字空间里面定义类型,而不是外面

11. Default parameters should not be used
不应该使用参数默认值(C#没有参数默认值)

12. Define accessors for attribute arguments
应该为特性(特性)的构造方法参数定义访问器,其名字跟构造方法参数仅首字母大小写不一样

13. Do not catch general exception types
不要捕捉普通的异常(即System.Exception)

14. Do not declare protected members in sealed types
不要在封闭类型中定义受保护的成员

15. Do not declare static members on generic types
不要在泛型类型中使用静态成员

16. Do not declare virtual members in sealed types
不要在封闭类型中定义虚成员

17. Do not declare visible instance fields
不要定义可见的(public/internal)实例域变量

18. Do not expose generic lists
不要直接暴露范型表

19. Do not hide base class methods
不要隐藏(使用或者不使用new)基类的方法

20. Do not nest generic types in member signatures
不要在成员的签名(参数或者返回值)中嵌套泛型类

21. Do not override operator equals on reference types
不要在引用类型中重载==操作符

22. Do not pass types by reference
不要使用引用(ref or out)传递类型

23. Enum Storage should be Int32
枚举应该是 Int32 类型的

24. Enumerators should be strongly typed
枚举器应该是强类型的

25. Enums should have zero value
枚举应该具有0值

26. Generic methods should provide type parameter
泛型类的方法应该提供类型参数

27. ICollection implementations have strongly typed members
集合接口的实现中应该使用强类型的成员

28. Implement standard exception constructors
自定义的异常应该实现异常类的四个标准构造方法

29. Indexers should not be multidimensional
索引不应该是多维的

30. Interface methods should be callable by child types
接口方法应该可以被子类调用

31. Lists are strongly typed
表应该是强类型的

32. Mark assemblies with assembly version
用程序集版本标示程序集

33. Mark assemblies with CLSCompliant
使用CLSCompliant特性标示程序集

34. Mark assemblies with ComVisible
使用 System.Runtime.InteropServices.ComVisibleAttribute 特性标示程序集

35. Mark attributes with AttributeUsageAttribute
使用 AttributeUsageAttribute 特性标示特性类

36. Mark enums with FlagsAttribute
含有组合的枚举应该使用FlagsAttribute特性标示,相反则不应该

37. Members should not expose certain concrete types
成员(返回值或者参数)不应该暴露具体类型,尽量使用接口

38. Move pinvokes to native methods class
将调用移到本地方法类(不是很理解)

39. Nested types should not be visible
嵌套类型不应该是可见的

40. Override methods on comparable types
可比较类型应该重写 equals 等方法

41. Override operator equals on overriding add and subtract
在重写+和-运算的时候应该同时重写==操作符

42. Properties should not be write only
属性不应该是只写的

43. Provide ObsoleteAttribute message
过时的成员应该使用ObsoleteAttribute特性标示,并提供相应的Message提示使用者

44. Replace repetitive arguments with params array
使用参数数组代替重复的参数

45. Static holder types should be sealed
仅含有静态成员的类型应该声明为封闭的

46. Static holder types should not have constructors
仅含有静态成员的类型应该具有构造方法

47. String uri overloads call system uri overloads
使用string类型的uri参数的重载应调用系统的使用URI类型参数的重载

48. Types should not extend certain base types
类型不应该从具体的类(已经过派生的类)继承,比如异常类不应该从ApplicationException继承,而应该从System.Exception继承

49. Types that own disposable fields should be disposable
含有可释放成员的类型应该是可以释放的(实现IDisposable接口)

50. Types that own native resources should be disposable
使用了非托管资源的类型应该是可以释放的(实现IDisposable接口)

51. Uri parameters should not be strings
Uri 参数不应该是string类型的

52. Uri properties should not be strings
Uri 属性不应该是string类型的

53. Uri return values should not be strings
Uri 类型的返回值不应该是string类型的

54. Use events where appropriate
在适当的时候使用事件

55. Use generic event handler instances
使用泛型的事件处理器实例

56. Use generics where appropriate
在适当的时候使用范型

57. Use integral or string argument for indexers
索引器应该使用整数或者字符串类型的参数

58. Use properties where appropriate
在适当的时候使用属性(而不是以Get或者Set开头的方法)

59. Validate arguments of public methods
对public的方法的参数应该在方法开头处进行检验(比如是否为null的检验)

二、 Globalization(全球化)
1. Avoid duplicate accelerators
避免在顶层控件中使用重复的快捷键(加速键)
2. Do not hardcode locale specific strings
不要对本地的特殊字符串(比如特殊的系统路径)进行硬编码

3. Do not pass literals as localized parameters
不要把文本作为需要本地化的参数直接传递(尽量使用资源文件)

4. Set locale for data types
为某些数据类型设定区域和语言属性(DataSet和DataTable的locale属性)

5. Specify CultureInfo
指定文化信息(地域和语言信息),在调用接受System.Globalization.CultureInfo 类型参数的方法时应该传递文化信息

6. Specify IFormatProvider
指定格式供应器,在调用接受System.IFormatProvider 类型参数的方法时应该传递格式供应器

7. Specify MessageBoxOptions
指定MessageBox的选项,在调用MessageBox.Show方法时应该传递System.Windows.Forms.MessageBoxOptions,特别在某些从右向左阅读习惯的区域
 
三、 Interoperability(互操作性)
1. Auto layout types should not be ComVisible
自动布局的类型不应该对Com可见(设置System.Runtime.InteropServices.ComVisibleAttribute特性为false)

2. Avoid int64 arguments for VB6 clients
避免使用int64类型,如果成员可能被Visual Basic 6 COM clients调用

3. Avoid non-public fields in ComVisible value types
避免在一个标记有ComVisible特性的值类型里面包含非公有的实例域
 
4. Avoid overloads in ComVisible interfaces
避免在一个标记有ComVisible特性的接口内声明重载

5. Avoid static members in ComVisible types
避免在一个标记有ComVisible特性的类型

6. Call GetLastError immediately after pinvoke
进行pinvoke以后应该立即使用GetLastError读取错误信息

7. Com registration methods should be matched
Com注册方法(标记有System.Runtime.InteropServices.ComRegisterFunctionAttribute特性的方法)应该是配对的(同时具有一个标记有System.Runtime.InteropServices.ComUnregisterFunctionAttribute的方法与之匹配)

8. Com registration methods should not be visible
Com注册方法应该是不可见的

9. Com visible type base types should be ComVisible
标记有ComVisible特性的类型的基类同样应从标记有ComVisible特性的类继承

10. Com visible types should be creatable
标记有ComVisible特性的类型应该能够使用默认构造器构造

11. Declare PInvokes correctly
正确定义PInvokes

12. Do not use AutoDual ClassInterfaceType
不要把System.Runtime.InteropServices.ClassInterfaceAttribute特性的值设置为System.Runtime.InteropServices.ClassInterfaceType.AutoDual

13. Mark boolean pinvoke arguments with MarshalAs
布尔型的pinvoke参数应该使用System.Runtime.InteropServices.MarshalAsAttribute特性标记

14. Mark ComSource interfaces as IDispatch
将System.Runtime.InteropServices.ComSourceInterfacesAttribute特性标记为System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIDispatch.

15. PInvoke entry points should exist
Pinvoke应该存在入口点

16. PInvokes should not be visible
Pinvoke应该是可见的

四、 Naming(命名)
1. Avoid language specific type names in parameters
避免在参数中使用与特定语言相关的类型(用Uint16代替Ushort)

2. Avoid type names in parameters
避免在外部可见的参数中使用类型名

3. Compound words should be cased correctly
复合词应该使用正确的大小写(不要将Mutlipart写成MultiPart,也不要将ToolBar写成Toolbar,FileName写成Filename)

4. Do not name enum values 'Reserved'
不要在枚举值中使用保留字

5. Do not prefix enum values with type name
不要在枚举值使用类型前缀(比如不要使用Digital之类的前缀)

6. Events should not have before or after prefix
事件的名称不应该包含before和after前缀(尽量使用ing和ed的后缀)

7. Flags enums should have plural names
标记有System.FlagsAttribute特性的枚举应该使用复数形式的名称

8. Identifiers should be cased correctly
标示符(名字空间、类名、属性名、接口名、方法名等)应该使用正确的大小写(通常以大写开头,以后的每个单词都首字母大写)

9. Identifiers should be spelled correctly
标示符应该可以被正确的划分为不同的单词

10. Identifiers should differ by more than case
标示符应该不止有大小写上的不同(因为某些语言是不区分大小写的)

11. Identifiers should have correct prefix
标示符应该使用正确的前缀(接口应该使用字母I开头)

12. Identifiers should have correct suffix
标示符应该使用正确的后缀
System.Attribute/Attribute
System.EventArgs/EventArgs
System.Exception/Exception
System.Collections.ICollection/Collection
System.Collections.IDictionary/Dictionary
System.Collections.IEnumerable/Collection
System.Collections.Queue/Collection or Queue
System.Collections.Stack/Collection or Stack
System.Collections.Generic.ICollection/Collection
System.Collections.Generic.IDictionary/Dictionary
System.Data.DataSet/DataSet
System.Data.DataTable/Collection or DataTable
System.IO.Stream/Stream
System.Security.IPermission/Permission
System.Security.Policy.IMembershipCondition/Condition
An event-handlerdelegate./EventHandler

13. Identifiers should not contain underscores
标示符不应该使用下划线

14. Identifiers should not have incorrect prefix
标示符不应该使用不正确的前缀(比如不应使用一个字母作为前缀)

15. Identifiers should not have incorrect suffix
标示符不应该使用不正确的后缀(不要在不正确的地方使用12中提及的后缀名,和Delegate、Enum、Flags for an enumeration、Impl等后缀名)

16. Identifiers should not match keywords
标示符不应该与系统关键字冲突

17. Long acronyms should be pascal-cased
长度大于等于3的缩写词应该使用pascal的命名规则,即首字母大写

18. Only FlagsAttribute enums should have plural names
只有标记有System.FlagsAttribute特性的枚举的名称才应该使用复数,其他时候应该使用单数

19. Parameter names should match base declaration
派生项的参数名应该同基项相吻合(派生类重写或实现的方法应该同基项具有相同的参数名)

20. Parameter names should not match member names
方法的参数名不应该同类或接口的成员名一样

21. Property names should not match get methods
属性名字不应该同Get开头的方法的名称的后半部分相同

22. Resource string compound words should be cased correctly
包含符合单词的资源字符串应该使用正确的大小写(每个单词的首字母大写)

23. Resource strings should be spelled correctly
资源字符串应该正确的拼写

24. Short acronyms should be uppercase
短的首字母缩写词应该全部大写(比如DB,CR)

25. Type names should not match namespaces
类型的名字不应该与名字空间的名字相同
 
26. Use preferred terms
优先使用某些项目或者名称,以下这些,后者为优先使用的
ComPlus/EnterpriseServices
Cancelled/Canceled
Indices/Indexes
LogIn/LogOn
LogOut/LogOff
SignOn/SignIn
SignOff/SignOut
Writeable/Writable

五、 Performance(性能规则)
1. Avoid calls that require unboxing
避免调用一个方法,它返回object类型,而你需要的是一个值类型(需要对返回值进行拆箱操作)

2. Avoid costly calls where possible
尽可能的避免进行代价高昂的调用

3. Avoid excessive locals
避免使用过多的局部变量(多于64个,部分可能是编译器生成的)

4. Avoid uncalled private code
避免声明在程序集内从来未被调用的私有成员(private和internal),以下除外:
? 明确的接口成员
? 静态构造方法
? 静态的Main方法(不含参数或仅包含一个string数组的参数的)
? 序列化构造方法
? 标记有System.Runtime.InteropServices.ComRegisterFunctionAttribute或者 System.Runtime.InteropServices.ComUnregisterFunctionAttribute.特性的
? 重写的方法

5. Avoid uninstantiated internal classes
避免声明不会被实例化的内部类,以下情况除外
? 值类型
? 抽象类型
? 枚举
? 委托
? 编译器生成的数组类型
? 仅含有静态成员的内部类

6. Avoid unnecessary string creation
避免创建不必要的string实例(犹指‘通过ToLower和ToUpper创建的string’),含以下情况
? 对于同一个string实例多次调用ToLower和ToUpper(建议:将返回值赋给一个局部变量,然后使用此局部变量)
? 使用equals,’==‘,!=比较‘通过ToLower和ToUpper创建的string’(建议:使用String.Compare比较)
? 向一个System.Collections.Specialized.HybridDictionary类型的成员传递‘通过ToLower和ToUpper创建的string’(建议:HybridDictionary具有一个指示是否忽略大小写的参数的构造方法重载,使用此重载并传递一个true值进去)

7. Avoid unsealed attributes
避免声明未封闭的特性(attributes)(建议:声明为sealed/ NotInheritable-vb.net或者abstract)

8. Avoid unused parameters
避免在方法声明中包含不会被使用的参数,以下情况除外
? 代理引用的方法
? 作为事件处理程序的方法
? 抽象方法(abstract)
? 虚方法(virtual)
? 重写的方法(override)
? 外部方法(extern)

9. Dispose methods should call SuppressFinalize
Dispose方法应该调用SuppressFinalize,以请求系统不要调用其Finalize方法

10. Do not call properties that clone values in loops
不要在循环中使用‘返回一个Clone的对象的属性’(每次返回‘引用不同’的对象,会导致创建大量的相同的对象)

11. Do not cast unnecessarily
不要进行不必要的类型转换(特别是尝试性的转换,建议:在转换前可以使用is操作符来判断转换能够成功)

12. Do not concatenate strings inside loops
不要在循环内串联string(建议:使用StringBuilder代替string)

13. Do not ignore method results
不要忽略方法的返回值(通常调用string的方法会返回新的string)

14. Do not initialize unnecessarily
不要进行不必要的初始化(比如将类成员初始化为它的默认值)

15. Initialize reference type static fields inline
在静态成员声明的时候直接初始化或者调用静态方法初始化(不要使用静态构造方法来初始化静态成员,静态构造方法会影响性能),以下情况除外:
? 初始化对全局状态的影响是代价高昂的,而且类型在使用前不需要进行初始化的
? 在不需要访问该类型的静态成员的情况下,全局状态的影响就可以被访问到的

16. Override equals and operator equals on value types
对于公有的值类型,重写equals方法和’==‘操作符(如果你期望用户对实例进行比较或者排序,或者作为哈希表的键)

17. Prefer jagged arrays over multidimensional
使用锯齿形数组代替多维数组(当数组各元素的长度可能不一致时)
注意:公共语言规范(CLS)不支持锯齿数组

18. Properties should not return arrays
公有类型的属性不应该返回数组(数组类型的属性无法进行写保护,即使是只读的,除非每次返回不同的拷贝,但是这样会让调用者产生迷惑。建议:改成方法)

19. Remove empty finalizers
移除空的终结器

20. Remove unused locals
移除未使用过的局部变量

21. Test for empty strings using string length
使用length属性测试字符串是否为空(原因:不要使用==””、==String..Empty、Equals(“”)等方法,使用Length属性的效率是最高的;null==empty比较不会抛出异常;在DotNetFrameWork2里面可以使用IsNullOrEmpty方法来判断字符串是否为null或者empty)

22. Use literals where appropriate
在适当的时候使用const代替static readonly(const是编译时赋值的)

 

posted @ 2009-02-23 13:19 我的地盘我做主 阅读(65) 评论(0) 编辑

本文转载自《南辕北辙的心情》, 感谢Ryan的分享。

微软的Windows Vista已经发布有一段时间了,相信很多朋友都已经在使用这个最新的操作系统,毋庸置疑的是这款操作系统真的给大家带来了许多的惊喜,但是惊喜的同时也有一些操作的麻烦。
IIS在windows xp专业版中的设置是非常简单的但是在windows vista中,IIS7的使用并不是那么方便的,虽然没有太多的难度,但是由于vista考虑到系统的安全性,还是需要一些设置才能正常使用ASP+Access,具体教程写下来以供大家使用。原来这篇教程发到了远景论坛,由于时间仓促没有详细的写,现在有时间了可以正式写一下了,以图片为主,介绍在windows vista下面IIS7的安装、设置、调试ASP+Access的具体方法和步骤,废话少说让我们开始吧!
第一步:在windows vista下面IIS7的安装方法。
             进入Vista的 控制面板,选择左侧的 打开或关闭Windows功能

第二步:安装IIS7的选项设置。
单击后会出现安装Windows功能的选项菜单,注意选择的项目,下面这张图片把需要安装的服务都已经选择了,因为Vista的IIS7的默认安装选项中是不支持ASP和ASP.NET的,因此在安装的时候我们必须手动选择你需要的功能。

 

 

 

第三步:安装完成后,再次进入 控制面板,选择 管理工具,在管理工具下面会多出 IIS6的管理工具 选项,选择红线标记的选项进行IIS7的设置。



第四步:设置IIS7。选择 Default Web Site,并双击 ASP 的选项,



IIS7中ASP 父路径 是没有启用的,要想方便的使用ASP,首选要 开启父路径,选择True,这一步搞定父路径选项。



第五步:IIS7的站点设置。 右键单击 Default Web Site 选项,选择红线标记的 高级设置 选项。



在下图这个对话框中设置网站的 主目录访问的端口 等设置。



按照上面的步骤IIS7的设置已经基本完成了,但是这个时候,在Windows vista中只能调试ASP的程序,但是还是无法调试ASP+Access程序,这是因为windows vista的目录权限问题,下面只剩最后一步,设置目录的权限。


第一步:需要设置权限的目录路径如下:
系统安装盘:\Windows\ServiceProfiles\NetworkService\AppData\Local,最好是手动输入路径,因为从Appdata的文件是隐藏的。右键单击 Temp文件夹,选择 属性


第二步:选择 安全 选项,单击 编辑 按钮,进入 编辑权限 的对话框。



第三步:选择 添加 按钮,添加用户。



第四步:在 选择用户或组 的对话框中,在 输入对象名称来选择 的表单中,输入大写字幕A后,单击 确定,系统会自动显示所有带有字幕A的系统用户。



第五步:在系统列出的用户中,选择 Athenticated Users 这个用户,并单击确定




第六步:添加完成这个用户以后,选择添加的用户,单击 完全控制,然后 确定,这样,Temp的访问权限搞定了。系统会有安全提示,选择确定就可以了,试一下,是不ASP+Access可以运行了。这样搞定了。

posted @ 2009-02-06 15:28 我的地盘我做主 阅读(171) 评论(0) 编辑