本文是我前几天给公司里面同事培训C#时的一个讲义,今天抽时间进行了下润色,主要介绍了下我这几年开发C#应用程序积累的一些经验。虽然本文围绕着C#语言展开,但大部分场景同样也适用于VB.NET的开发。
一、开发环境
1、开发人员的开发环境以框架要求为准。如统一使用VS2010开发环境与.NET Framework 4.0等。
如果安装了更高版本的VS开发工具,需要在提交sln文件到SVN前修改标题,否则其他开发者更新下来sln后,可能会出现无法用低版本IDE打开的问题。
如用VS2012创建的工程,需要修改sln文件,将Format Version由12.00改为11.00,Visual Studio 2012改为2010。
在程序集属性中可以指定编译目标平台,如下面指定了目标平台为.NET Framework 4.0
2、如果在程序中需要用到指针,需勾选“允许不安全代码”。一般不要勾选“优化代码”,这可能导致编译器在对多线程程序做出错误的优化操作。
3、生成事件命令行可以在程序生成前或生成后执行Windows命令,一般用于将本地的配置文件等复制到生成后的目录中。
二、客户端架构
客户端的架构人员一般由项目组中一个专门的人来担任。这个人需要具备一定C#(或VB.NET)开发经验。
整体客户端的架构工作包括:
1、为各业务系统建立专门的程序集,简化各业务系统编码人员的编码。
2、处理项目开发过程中的非业务问题,找出问题出现原因。
3、处理、分配并解决开发过程中遇到的技术问题,包括提出方案、开发程序、编写文档工作。
三、通讯功能
通讯功能是客户端程序最为重要的功能之一,一般在客户端搭建之初,由架构人员统一调试成功并给出通讯接口类。所有编码人员按方法调用即可。
通讯功能需要注意的点有:
1、通讯分为同步通讯和异步通讯,同步通讯一般用于处理实时性要求高的接口,大多数接口都使用同步通讯。异步通讯一般用于提供一些尽力而为的服务,异步通讯也可以用于实现一些不希望因网络原因出现卡顿影响整体效果的功能(如监控)。
2、同步通讯的通讯超时时间,一般根据程序实际使用场景进行设定。对于一些运行时间可能非常长的接口(如日终时执行批处理任务),可以酌情加长超时时间。
3、断线重连机制,需要确保断线和重连功能,特别是要保证重连后刷新出来的数据在覆盖老数据时,一些相关处理逻辑的正确性。
4、(这点是对开发人员说的)对于会更改数据库内数据的接口,一个按钮最多调用一次。否则会出现下面的情况:一个按钮先后执行A、B操作,执行B操作失败时,A操作无法回滚。
案例:Long类型数据0的前后台传递
问题描述:
后台程序用Java语言编写,前台程序用C#编写时。因为Java中的Long类型(不是long类型)数据是可以为null的,C#中的long类型数据是不可以为null的,后者的默认值是0。如何确定前台程序收到的一个long类型变量在后台是0还是null?
处理办法:
在生成值类型接口时,需要将.NET中的值类型数据,写成两个属性,第一个属性用于存储这个数据的值,第二个属性用于标记是否为null,如下图所示:
案例:因网速慢的问题导致重复提交
问题描述:
新增操作,第一次点击提交按钮时同步连接接收超时,但后台服务实际上已经处理了该问题,只是因为处理速度慢或网速慢导致接口调用时间超过了超时时间。如果数据不具备唯一性约束,第二次点击“提交”时,会重复提交一条新的数据。
处理办法:
使用令牌机制可以解决此问题,即在前台窗口建立时向后台申请一个唯一的令牌,第一次调用接口时,核对令牌,并在后台令牌库中标记此令牌已使用。第二次调用时,如第一次调用已经成功,核对令牌时就会提示异常。
四、日志功能
日志分为框架日志和各业务系统日志,这两类日志需要分开存放,各业务系统日志也需要分开存放,便于日后排查问题。日志中要说明问题发生的时间、问题等级、问题描述,如果是异常信息,还应提供调用堆栈。
日志等级一般由各项目自己定义,可以参考下面的方法分级:
Debug:调试类信息,程序开发阶段为方便开发人员自身调试输出的信息
Info:日志类信息,一些开发人员认为应该打印出来的信息
Warning:警告类信息,不影响流程但又应引起重视的问题,分到警告级别
Error:错误类信息,弹出的异常一般分到此等级中
将日志分级还有一个好处,就是可以通过配置对程序输出的日志进行过滤,如提供给客户使用的日志,不打印调试类信息。
五、配置功能
一个系统的配置功能,分为全局配置、客户端配置和个性化配置三类
1、全局配置,放在后台管理,所有的客户端在开启后都会向后台请求全局配置。全局配置一般适用于一些可能会出现变更且出现变更后方便平台统一修改的内容,如电话号码的正则校验规则。
2、系统配置,系统配置是每个客户端保存一份的配置。一般用于记录客户端维度的设置,如上次登录用户名、通信配置等。
3、个性化配置,客户端每个操作员都可以保存一份自己的配置。可以采用key-value(键值对)的形式进行存储。
如下图就是一个个性化配置的配置文件:
六、编码规范
编码规范决定了一个小组是否可以编写出风格相近的代码。一般推出编码规范的执行力受团队的默契程度和开发人员的经验影响。
1、基本编码规范
基本编码规范是编码的底线,所有编码人员必须无条件遵守,如标识符的命名规则(控件、接口命名使用匈牙利命名法)、文档首部注释规则(说明开发人员、创建日期等内容)。基本编码规范同时也是代码审查时候的一个依据。
2、项目编码规范
项目编码规范,是适用于当前项目的临时性编码规范,比如工具类的调用方法及调用顺序等,需要各个项目组写入文档。
3、C#编码风格与Java编码风格的区别(举两个例子)
C#的大括号写在下面,Java的大括号写在后面
C#的方法名首字母大写,Java的方法名首字母小写
4、在“调试”菜单下的“选项和设置”中可以设置编码风格
七、缺陷处理
编码过程中,会遇到各种各样的程序缺陷。程序缺陷大致分为三类:
1、开发环境固有缺陷
这类缺陷很多都是操作系统缺陷,只能设法绕过,或是想其他方法解决。这类缺陷解决时,不能只局限于百度搜索,要学会使用英文在一些国外技术网站(如MSDN论坛、StackOverflow等)上搜索答案。
说一下我遇到的两个C#的控件问题及解决方案:
TreeView控件复选框联动时鼠标点击过快导致的显示不正确的问题
http://my.oschina.net/Tsybius2014/blog/551358
ListView使用数据分组功能(ListViewGroup)后,点击组标题,为组内数据赋的颜色就会褪为黑色
http://my.oschina.net/Tsybius2014/blog/610051 (第二节)
2、二次开发缺陷
如果你使用的是公司研发部门提供的框架,或是使用了从其他商业机构购买的内容,与之有关的问题都可以求助相关技术部门。一般来说,较新的框架问题也较多。另外,尽量不要使用已经没有人维护的框架和库。
3、自身缺陷
记住,你自身犯错误的几率远比上面两个地方出现错误的几率大!减少自身缺陷的方法,就是要多做自测,多积累编码经验,出现问题多从自己身上找原因。代码审查也可以在很大程度上消灭代码中缺陷,巴菲特曾说,“与其从自己身上吸取教训,不如从其他人的错误中吸取教训”,开发人员间经常交流、相互之间多做一些代码审查,往往可以让他们的开发水平快速成长。
八、再议客户端架构
下面说一说客户端架构中一些功能的编码要点
1、自动锁屏
自动锁屏需要建立钩子监控鼠标移动、鼠标点击、键盘按键三类事件,监控事件在客户端打开时注册,在客户端关闭前一定要注销。否则在关闭时触发可能引起客户端的崩溃。
2、自动刷新
自动刷新功能有多种实现方式,各有利弊。使用Timer组件实现的自动刷新,简便易用。也可以使用多线程自己实现自动刷新,但新手操作多线程可能会有死锁、访问已释放资源等风险。
3、自定义控件、组件
很多时候,自定义控件、组件可以减少重复工作量。对于不同页面都需要重复添加的小功能,使用自定义控件、组件实现它们非常合适。比如DataGridView窗格控件中,实现一个列类型,在输入值为单位为Byte的数字后,会在显示内容时自动将其转换为XXXKB、XXXMB等,很多个DataGridView都可能需要这个功能,但我们只实现一次就够了。
举几个我写的自定义控件的例子:
基于三个ListView的名单比较控件:http://my.oschina.net/Tsybius2014/blog/610051
基于LinkedLabel的超链接控件:http://my.oschina.net/Tsybius2014/blog/549291
4、内置浏览器
如果要在C#客户端内使用浏览器,要特别小心,因为兼容性问题非常多。微软提供的WebBrowser控件默认使用的内核配置在注册表中,一般Win7系统这个配置都是IE7(即使你电脑上的IE是更高版本如IE8)。使用其他浏览器内核开发客户端,也需要注意多浏览器兼容、缓存刷新等问题。
5、反射、特性等高级语言功能
反射(Reflection)、特性(Attribute)这类高级语言在架构设计中起着非常重要的作用。特性功能类似Java语言的注解。
九、客户端的发布
客户端出包是一个比较重要的环节。
我开发过一个工具用于给程序自动打包,其打包步骤如下:
1、读取打包工具的配置项(如rar.exe、makensisw.exe地址等)
2、删除所有pdb文件
3、复制一份用于自动更新包的副本,删除配置文件等可能会随着用户使用不断更新的文件
4、打开NSIS程序,编译nsi脚本为程序制作安装包
5、使用WinRAR将程序安装包 、自动更新内容制作到压缩包中,打包完毕
需要注意的是:
1、打包前要先删除冗余文件,如*.pdb文件。对于自动更新端,还要删除那些可能会随着每次登录发生改变的文件和目录(如本地缓存数据用的文件等)
2、WinRAR程序(rar.exe)和NSIS编译工具(makensisw.exe)都提供了功能强大的命令,可以利用这些命令完成很多自动化操作内容
十、一些其他需要注意的问题
①、防止开发过程中的SVN冲突
前台C#客户端中的SLN和CSPROJ文件,在满足条件后应立即更新到SVN
Q:什么时候需要提交 *.SLN 文件?
A:以下情况下需立即更新SLN文件
1)修改解决方案属性(如设置启动项目等),应立即更新SLN文件
2)新增、删除解决方案中的程序集后,应立即更新SLN文件
Q:什么时候需要提交 *.CSPROJ 文件?
A:以下情况下需立即更新CSPROJ文件
1)修改程序集属性(如设置版本号,设置生成事件命令行等),应立即更新CSPROJ文件
2)添加类、窗体或其他文件到程序集下,无论使用任何方法(添加现有项或手工拖入),都需要先将文件ADD到SVN,然后立即更新CSPROJ文件
3)删除某一个程序集下的文件,需要先在解决方案中删除这个文件,再在对应目录上从SVN更新下来这个文件,在SVN上DELETE掉该文件,最后提交CSPROJ文件
4)上传、删除资源文件(Resource)后,应立即更新CSPROJ文件
解决文件更新冲突的办法:
1)同一子系统中,COMMIT完毕后立即通知其他人UPDATE
2)对于他人未提交解决方案或程序集信息的情况,如果在工作时间或当事人在场,沟通解决,否则从速解决
3)如果已经存在冲突,则协商解决
另外需要注意的是:上传文件前自己要先编译通过,对于吃不准的情况,可以自己建立一个新文件夹CHECKOUT下来一份试着编译一下
②、编写好一个界面后,记得设定该界面的Tab键顺序
修改Tab键顺序的办法为:
1、进入该页面的设计器界面
2、在VS的【视图】菜单下找到【Tab键顺序(B)】
3、按顺序依次点击各个需要获取焦点的控件
4、在VS的【视图】菜单下找到【Tab键顺序(B)】,再按一次该按钮退出编辑Tab键顺序状态
主要需要设置Tab键顺序的地方:
1、有很多输入项需要用户输入的窗口,各输入框需要设置Tab键顺序
2、带有查询条件的查询窗口,查询条件需要设置Tab键顺序
③、表单的导入和导出
以Excel文件为例:
表单的导入可以看做是一个文件上传加上后台解析的过程。在进行文件解析时,需注意除提供对 MS Office的支持外,很多机构要求对WPS也提供支持。另外一点就是需要对Office2007之前和之后的Excel进行分类讨论,因为xls和xlsx的解析机制是不一样的。
表单的导出分为前台导出和后台导出,前台导出是通过前台程序直接调用Office类库(或其他类库,下同),后台导出的即由后台生成文件,通过文件下载的方式传递到前台进行导出。一般推荐使用后台导出,因为这样可以避免因用户环境问题引发的导出失败。
④、C#与其他语言的交互
C#语言和VB.NET语言是相通的,C#可以很容易地使用VB.NET语言编译出的DLL。
C#语言与非托管的C++代码编译出的DLL库也可以相互调用,不过要事先在程序中对这个DLL进行声明。
END