您的位置:首页 > 其它

[收藏] .Net平台开发的技术规范与实践精华总结

2007-05-05 10:18 441 查看
以下是本人对.Net平台开发实践的一些点滴总结。这里的技术规范主要是开发过程的代码规范、数据库设计规范、Com和.Net互操作规范;实践精华是对技术实践过程中的部分总结。

一、代码规范

良好的代码风格来自于同一的代码规范。风格良好的代码不仅具备可读性和可维护性,同时也给人行云流水、赏心悦目之快感。
据Microsoft公司统计,基于微软平台的开发中,有70-80%的印度工程师在完成同类算法或者模块时,使用的代码基本一致;而相同的调查中只有20%的中国工程师们是基本一致的。这说明我们的代码生产过程亟待规范。

实义命名

类型、变量、常量、方法等标识符一律采用对应的英文实义;如果涉及到两个独立的实义单词,则中间用下划线间隔或者单词首字母大写(两种方式都可以);如果标识符的长度超过了30个字母,则基本上以英文单词发音的重读音节取选出三个字母,如Repeater用rpt,Management用mgt。

大小写规则

目前一般有两种大小写规则:
Pascal大小写形式,所有单词第一个字母大写,其他字母小写。
Camel大小写形式,除了第一个单词,所有单词第一个字母大写,其他字母小写。
n 类名使用Pascal大小写形式
public class HelloWorld(或者Hello_World,以下同,不再赘述)
{
...
}
n 方法使用Pascal大小写形式
public class HelloWorld()
{
void SayHello(string name)
{
...
}
}
n 变量和方法参数使用Camel 大小写形式
public class HelloWorld()
{
int totalCount = 0;
void SayHello(string name)
{
string fullMessage = "Hello " + name;
...
}
}
n 不要使用匈牙利方法来命名变量
以前,多数程序员喜欢把数据类型作为变量名的前缀而m_作为成员变量的前缀。例如: string m_sName;int nAge;
然而,这种方式在.NET编码规范中是不推荐的。所有变量都用Camel 大小写形式,而不是用数据类型和m_来作前缀。
用name,address,salary等代替nam,addr,sal。
别使用单个字母的变量象i,n,x 等。使用 index,temp等。用于循环迭代的变量例外:
如果变量只用于迭代计数,没有在循环的其他地方出现,允许用单个字母的变量命名,而不是另外取实义名。
文件名要和类名匹配,例如,对于类HelloWorld,相应的文件名应为helloworld.cs。

缩进和间隔

n 缩进用TAB,不用 SPACES。
n 注释需和代码对齐。
n 遵循VS2005的自动对齐规则,不要人为的调整。
n 用一个空行来分开代码的逻辑分组。
n 在一个类中,各个方法的实现体必须用空行间隔,大括弧“{}”需独立一行。
n 在每个运算符和括号的前后都空一格。如:
If ( showResult == true )
{
for ( int i = 0; i < 10; i++ )
{
//
}
}
而不是:
if(showResult==true)
{
for(int i= 0;i<10;i++)
{
//
}
}

良好的编程习惯

n 避免使用大文件。如果一个文件里的代码超过300~400行,必须考虑将代码分开到不同类中。
n 避免写太长的方法。一个典型的方法代码在1~30行之间。如果一个方法发代码超过30行,应该考虑将其分解为不同的方法。
n 方法名需能看出它作什么。别使用会引起误解的名字。如果名字一目了然,就无需用文档来解释方法的功能了。
n 一个方法只完成一个任务。不要把多个任务组合到一个方法中,即使那些任务非常小。
n 使用C# 的特有类型,而不是System命名空间中定义的别名类型。如:
int age;
string name;
object contactInfo;
而不是:
Int16 age;
String name;
Object contactInfo;

这么做是基于如下两点原因:(1)规范性和一致性;(2)便于跨语言平台的移植。

n 别在程序中使用固定数值,用常量代替。别用字符串常数,尽量用资源文件。
n 避免使用很多成员变量,声明局部变量,并传递给方法。
n 不要在方法间共享成员变量,如果在几个方法间共享一个成员变量,那就很难知道是哪个方法在什么时候修改了它的值。必要时使用enum,别用数字或字符串来指示离散值。
n 别把成员变量声明为 public或 protected。都声明为private 而使用 public/protected 的Properties。
n 不在代码中使用具体的路径和驱动器名,使用相对路径,并使路径可编程。永远别设想你的代码是在"C:"盘运行。你不会知道,一些用户在网络或"Z:"盘运行程序。
n 应用程序启动时作些“自检”并确保所需文件和附件在指定的位置。必要时检查数据库连接,出现任何问题给用户一个友好的提示。
n 如果需要的配置文件找不到,应用程序需能自己创建使用默认值。如果在配置文件中发现错误值,应用程序要抛出错误,给出提示消息告诉用户正确值。错误消息需能帮助用户解决问题。

注释

n 别每行代码,每个声明的变量都做注释。在需要的地方注释。
n 可读性强的代码需要很少的注释,如果所有的变量和方法的命名都很有意义,会使代码可读性很强并无需太多注释。行数不多的注释会使代码看起来优雅。
n 如果因为某种原因使用了复杂艰涩的原理,必须为程序配备良好的文档和详细的注释。
n 对注释做拼写检查,保证语法和标点符号的正确使用。

二、数据库设计规范

表格分类与命名

n 数据表的分类
u 系统表 支撑业务模型的数据表,如流程模型、系统管理相关表。
u 业务表 产品提供的针对业务的通用功能模块相关表,如通用业务查询等。
u 用户表 用户二次开发使用的与具体业务相关的数据表。
n 数据表的命名
u 所有表格命名一律以字母“T”开头(Table),并且用实义单词以下划线“_”间隔。
u 系统表 系统表前缀为:TSYS_
u 业务表前缀为:TBIZ_
u 用户表由用户自行定义,但是建议不要与系统表和业务表的命名规则重复。
n 字段的命名
字段的命名规则参照代码标识符的命名规则,但是注意避开数据库的保留字。比如不要采用这样的字段名:index,field,password,id,Oracle,SQL等等。
对于涉及到技术核心的系统表,为了防止剖析,建议采用类似“F1,F2,F3……Fn”的方式命名。但是不要采用“F0”,因为这个名称在某些数据库中不被允许,比如Interbase。

索引的建立

n 索引是一把双刃剑,索引将提高查询的效率,但是却降低了insert/delete/update 的效率。
n 通常情况下,对数据的编辑频度和时限要求远远低于对数据库的查询要求,因此对于记录很多且频繁查询的数据表,必须建立索引。
n 大多数数据库为主键字段自动创建索引,注意为外键创建索引。
n 不要索引大字段,这样作会让索引占用太多的存储空间。
n 尽量不要索引频繁编辑的小型表。
n identify字段不要作为表的主键与其它表关联,这将会影响到该表的数据迁移。如果考虑支持多数据库,建议主键采用程序生成的唯一值。
n 如果一个大型表需要频繁的做insert/delete/update操作,同时也需要做高并发量的查询,那么建议根据数据的访问频度对表作拆分,而后建立索引。

过程与函数

数据库厂商为了凸现自身的优势,都提供了丰富且个性化的过程与函数。
为了提升产品的伸缩性和数据无关性,请不要使用与特定数据库相关的过程与函数,也不推荐采用Store Procedure,建议使用应用服务器的中间层业务对象。

字段/域的定义

n 尽量避免使用Blob,如果一定要用,请不要索引blob,并且不要定义多个blob。
n 不要使用日期字段,改用字符串char(19)替代,如:2008-12-09 12:22:08。
n 对于确定长度的串,请固定字段类型的长度,如char(80),不要采用varchar。
n 对于值类型字段,请使用对应的数据库值类型,而不要用字符串。

三、Com和.Net互操作规范

.NET 技术已经成为微软平台的主流,但是在Win32时代开发了很多COM、DCOM组件,由于在开发COM组件时投入了大量的人力、财力,如何在.NET环境下重用这些COM组件就显得更有意义。
.NET支持运行时通过COM、COM+、本地WinAPI调用与未托管代码的双向互操作性,要实现互操作性,必须首先引入.NET Framework的 System.Runtime.InteropServices命名空间。
C#的语法为:
using System.Runtime.InteropServices;
1.NET访问API
.NET允许C#访问未托管的DLL的函数。如要调用Windows User32.dll的MessageBox函数:
int MessageBox(HWND hwnd,LPCTSTR lpText, LPCTSTR lpCaption,UINT uType)
可以声明一个具有DLLImport属性的static extern方法:
using System.Runtime.InteropServices;
[DllImport(“user32.dll”)]
static ertern int MessageBox(int hwnd,string text,string caption,int type);
然后在代码里面直接调用就可以了。这里要注意在调用返回字符串的API中使用StringBuilder对象。
2.NET访问COM组件
.NET调用COM组件比较容易,只要使用tlbimp.exe产生COM的装配形式的WarpClass,然后在.NET项目中调用即可。
注意COM的类型信息通过Type Library文件描述,.NET装配件是自描述的。Tlbimp的作用是从COM组件及其类型信息中产生自描述的装配件。
1.编写Com组件
编译生成一个ComAccount.dll。
2. 产生.NET可访问的包装类(assembly),使用TlbImp.exe产生.NET装配件。
TlbImp /out:NetAccount.dll ComAccount.dll
3.在.NET代码中访问
.NET代码只需引用NetAccount.dll,就可以像访问.NET的装配件一样访问COM组件。

四、异常处理

异常处理的原则

n 在应用程序级(线程级)错误处理器中处理所有的一般异常。遇到“意外的一般性错误”时,此刻错误处理器应该捕捉异常,给用户提示消息,在应用程序关闭或用户选择“忽略并继续”之前记录错误信息。
n 不必每个方法都用try-catch,当特定的异常可能发生时才使用。比如,当写文件时,处理异常FileIOException。
n 别写太大的 try-catch 模块。如果需要,为每个执行的任务编写单独的 try-catch 模块。这将有助于找出哪一段代码产生异常,并给用户发出特定的错误消息。
n 如果应用程序需要,可以编写自己的异常类。自定义异常不应从基类SystemException派生,而要继承于IApplicationException。
n 在开发阶段,不必在所有方法中捕捉一般异常。刻意的放纵异常,将帮助在开发周期发现大多数的错误。

异常处理的提示

n 不要捕捉了异常却什么也不做,看起来系统似乎在正常运行。如果这样隐藏了一个异常,将永远不知道异常到底是否发生,为什么发生。
n 发生异常时,给出友好的消息给用户。但要精确记录错误的所有可能细节,包括发生的时间,和相关方法,类名等。
n 永远别用像“应用程序出错”,“发现一个错误”等错误提示消息,而应给出类似“更新数据库失败,请确保登陆id和密码正确。”之类的具体消息。
n 显示错误消息时,还应提示用户如何解决问题。如:“更新数据库失败,请确保登陆id和密码正确。”,而不是仅仅说“更新数据库失败”。
n 显示给用户的消息要简短而友好。但要把所有可能的信息都记录下来,以助诊断问题。

异常处理的代码实例

推荐如下异常处理模式:
void ReadFromFile ( string fileName )
{
try
{
// 读文件.
}
catch (FileIOException ex)
{
// 记载异常日志
// 重抛具有针对性的异常信息
throw;
}
}

不推荐如下的异常处理模式:
void ReadFromFile ( string fileName )
{
try
{
// 读文件
}
catch (Exception ex)
{
// 捕捉一般异常将让我们永远不知道到底是文件错误还是其他错误
// 隐藏异常将我们永远不知道有错误发生。
return "";
}
}

五、对象实例的申请与释放

.Net平台的垃圾回收机制,可以自动的dispose不再引用的对象实例,所以很多开发人员并不主动释放申请的对象资源。事实上,在对象的生命周期结束之前是不会被释放的。
但是,很多时候当对象处于生命周期之内时,我们不再使用它,以便释放资源提升系统效率。因此,主动释放申请的资源显得很有必要。
永远不要把力所能及的事情交给操作系统,及时释放不再使用的资源是一个好习惯。

六、数据库访问

数据库访问永远是系统的瓶颈,选择高效、稳健的数据库访问模式是产品性能的基础保证。
n 永远不要假设你的应用系统构建与某个数据库之上,因此必须有统一的、透明的数据库访问机制。
n 采用ADO.Net访问数据库 基于效率和稳定性的考量,采用微软平台原生的数据库访问模式ADO.Net。使用ADO.Net可以通过OLEDB和ODBC两种模式访问数据库,我们建议使用数据库厂商提供的OLEDB模式,这种模式绕过了ODBC,使得数据库的游标性能大大提升,效率更佳。
n 不使用第三方的数据持久层 使用类似于Nhibernate之类的第三方数据持久层工具虽然可以提高开发的效率,但是却降低了系统的性能和弹性。性能对于产品而言,远远比开发效率重要的多,况且基于VS2005的开发,效率不是问题。请记住:第三方的工具永远不能成为你的产品核心技术;数据访问机制是系统的效率瓶颈,对
n 使用自主产权的数据对象 直接采用ADO.Net封装最底层的数据访问方法:插入、删除和更新,以及事务管理等;客户端和服务器端采用相同的数据访问机制,并设立连接缓冲池提升数据访问效率。

七、分布式事务管理

对于多层分布式应用而言,数据库事务呈现出“远程、分布”的特色,导致事务难以管理。
对于Ado.Net而言,事务绑定了数据库连接,因此必须在数据访问对象中对每一个数据库连接管理各自的事务或嵌套事务。如果要访问数据库,服务器上的数据访问对象将自动分配一个特定的连接,根据该连接ID执行数据操作;无论该事务分布于多少个远程客户端进程,服务器数据对象只需要锁定连接ID即可轻松进行事务管理。

八、智能客户端

智能客户端是易于部署和管理的客户端应用程序,它综合了瘦客户端和胖客户端的优点,通过统筹使用本地资源和到分布式数据资源的智能连接,提供快速响应的和丰富的交互式体验。
智能客户端分为Windows Form,Office Client,Mobile Client三种类型,具有如下特点:

n 利用本地资源
n 利用网络资源
n 支持偶尔连接的用户
n 提供智能安装和更新
n 提供客户端设备灵活性

.NET 框架基类库内嵌了支持智能客户端的丰富程序集,通过使用公共语言运行库 (CLR),可以利用任何受到 .NET 支持的语言来开发智能客户端。
智能客户端是瘦客户段的强大替代品,也是微软推荐的客户端模式。尽量使用智能客户端而不要使用浏览器。如果可以,请把你的客户端系统构建在Office平台上,如Outlook。

function hide(){showComment();}

# cnzjsxwine 发表于2007-02-09 18:25:00 IP:

ad_width=468;
ad_height=60;
adcss=2;
unionuser=19;
ad_type='j';
count=5;

n 使用C# 的特有类型,而不是System命名空间中定义的别名类型。如:

int age;

string name;

object contactInfo;

而不是:

Int16 age;

String name;

Object contactInfo;

在.NET框架程序设计中说,推荐使用System中定义的类型名。

# gongfs 发表于2007-02-09 19:53:02 IP:
这么做的目的,主要是为了规范和一致性。

# jyk 发表于2007-02-10 10:55:41 IP: 59.44.59.*
1、Nhibernate之类的第三方数据持久层工具 没有用了吗?
2、我认为开发效率更为重要,两年的时间开发出来一个高效的程序,还不如一个月里开发出来一个可以凑活用的程序。然后再用一年另11个月的时间逐步提升效率。

# platform 发表于2007-02-10 11:36:38 IP: 221.10.54.*
感觉应该对于页面的命名加一点内容

# Terrylee_1218 发表于2007-02-11 08:14:09 IP: 211.94.236.*
误人子弟啊!

“不使用第三方的数据持久层使用类似于Nhibernate之类的第三方数据持久层工具虽然可以提高开发的效率,但是却降低了系统的性能。性能对于产品而言,远远比开发效率重要的多。况且基于VS2005的开发,效率不是问题。”

# dulan 发表于2007-02-11 14:49:41 IP: 222.66.116.*
我还是赞成作者的观点的,在做大型应用,尤其是关键业务应用的时候,效率和稳定性永远是第一位的。毫无疑问,数据库就是瓶颈,使用nHerbinate之类的东西,看起来好像提高了开发效率,但是也提高不了多少,难道不需要做配置吗?难道不需要做大量的变更维护吗?如果直接采用底层数据源,效率要高得多,而且维护起来也方便。

第三方的数据持久曾是给懒汉们用的,是给那些初学者和入门级别的人使用,是给小型非关键应用系统用的。

# zxkid 发表于2007-02-12 08:38:31 IP:
第三方的数据持久曾是给懒汉们用的,是给那些初学者和入门级别的人使用,是给小型非关键应用系统用的。
===
非常同意

# dssw 发表于2007-02-14 11:46:52 IP: 121.233.34.*

基本同意楼主的意见。
规范对大型的系统确实非常重要。

# yuyan888 发表于2007-02-14 23:52:31 IP:
对于平台产品而言,我完全赞成楼主的观点。但是对于项目而言,使用第三方的东西还是有必要的,有时候很多因素迫使你不得不放弃规范,而追求开发速度。没有办法,理想距离现实总是很遥远。另外,希望看到楼主关于工作流方面的新文章,我曾拜读过楼主关于关于superflow的文章,十分的受启发。

# shoutor 发表于2007-02-24 13:32:08 IP: 222.130.222.*
程序的规范性太重要了,但有时很难协调

# marising 发表于2007-03-13 21:56:05 IP: 218.56.203.*
如果是一群高手,则不要用O-R mapping类的中间件;如果是一群新手,则用O-R mapping中间件更好。不要以为手工写数据库访问性能会更好,这种观点是彻底错误的,新手写出来的代码,根本不会考虑到数据库效率和性,只会带来更多的麻烦。

# weblogic2009 发表于2007-03-14 11:24:37 IP: 58.31.73.*

收藏!! ( 水晶报表杀手 -- e表, 它避免了大量的复杂SQL编写以及编程来准备数据。轻松实现复杂的统计报表,详见: http://my5155.meibu.com )

# weblogic2009 发表于2007-03-14 11:24:37 IP: 58.31.73.*
收藏!! ( 水晶报表杀手 -- e表, 它避免了大量的复杂SQL编写以及编程来准备数据。轻松实现复杂的统计报表,详见: http://my5155.meibu.com )

# changjunren 发表于2007-03-16 21:54:36 IP: 58.34.152.*
如果能够考虑页面的开发规范就更好了,的确不错,值得收藏。

# ITuring 发表于2007-03-17 17:20:22 IP: 61.157.97.*
上述编码规范能使代码显得好看些,但不便于阅读,比如
int age
而不是
Int16 age,
第一个好看是好看了,但有几个人能一看就知道age是几位的呢?
而第二个是不好看了点,但任何人都能一看就知道age是16位的。
“好看”不等于“方便阅读”,要知道在团队合作的项目里面,代码是随时要让别人阅读的,“方便阅读”也是一个优秀程序员写程序时所应该追求的,楼主是否能深入思考一下呢。

# qiaoshijituan 发表于2007-04-03 21:36:29 IP: 222.171.7.*
我给您发的邮件您看到了吗?请求您的帮助!

# gongfs 发表于2007-04-04 07:12:46 IP: 58.34.156.*
Qiaoshijituan,你好。我没有收到你的mail,我mail: gongfs@163.com,平时很少使用,也不是很安全。我基本上用工作邮箱,有什么问题你给我留言,如果不是特别的忙,我会看到的。

# qiaoshijituan 发表于2007-04-20 10:54:30 IP: 222.171.7.*

呵呵!才看到你的留言!下面是我大概4月10号左右给你发的,既然你不常用那个邮箱,那我就在这再发一次好了!-----
gongfs先生!
您好!
没想到您这么快就回复我了,我很是感到意外的惊喜。感谢您的慷慨帮助!能在百忙之中给予回复!
不过由于没想到您的论文是那么早的时候写的,97年,可我们学校的中国期刊网只能查到99年的,所以暂时我还没能找到。由于学校的万方数据库一直上不去,所以估计在网上是很难找到了。不过我还是会再试试的。
即便如此,我对您所给予的帮助仍然很是感谢!谢谢!
顺便想试试问两个问题,您要是有空或许能告诉我呢!我现在不知道用哪种语言开发专家系统好了?想用vb,又想用Visual Prolog ,可又不知道Visual Prolog在哪能搞到非免费版的,因为怕免费版的不能被vb所调用,又不想花太多钱了,也不知道15天能不能开发出一套故障诊断的专家系统。不知道Visual Prolog能不能自己构造,知识表达方法,与推理方法。都是菜鸟问题啊。您没空的话就不用理我了,呵呵!
再次感谢!
-----------------------------
那是过去的问题了,现在我已经想用vb做了,因为觉得prolog我实在是看不懂啊!没办法啊!又没有书讲!现在我的问题仍是没搞到你的论文,不知能否发我一份!我邮箱是ooqiaooo@126.com或是qiaoshijituan9@126.com谢谢!如果不方便发就算了!我再仔细研究一下!哈哈!现在还在看你的文章呢!

# ltp2008 发表于2007-05-03 22:05:28 IP: 222.209.208.*
代码编写的规范化将更有助于团队合作,提高工作效率,也便于日后的管理和维护。良好的编程习惯是从事大型项目开发的编程人员所必备素质。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: