C#编程规范(个人使用)
1.1.1 类名、公开方法名、属性名使用Pascal 大小写形式;
例如:
public class HelloWorld
{
void SayHello(string name)
{
...
}
}
如果私有事件方法利用Visual Studio.Net产生,不用修改成Pascal 大小写形式。例如:buttonSave的事件方法private buttonSave_Click不用将首字母修改成大写ButtonSave_Click,因为它不是公开方法。
1.1.2 变量和方法参数使用Camel 大小写形式
public class HelloWorld
{
int totalCount = 0;
void SayHello(string name)
{
string fullMessage = "Hello " + name;
...
}
}
1.1.3 不要使用匈牙利方法来命名变量
以前,多数程序员喜欢它-把数据类型作为变量名的前缀而m_作为成员变量的前缀。例如:
string m_sName;
int nAge;
然而,这种方式在.NET编码规范中是不推荐的。所有变量都用camel 大小写形式,而不是用数据类型的缩写和m_来作前缀。
表单变量(Form)、控件变量(如:TextBox, ComboBox ……)、和基本类型变量(如:int, long, string,……)可以用类型全称作为前缀。其它变量不用类型前缀。
用有意义的,描述性的词语来命名变量
1.1.4 应该用单词,不用缩写。别使用单个字母的变量像i, n, x 等,应该使用 index, temp等
例如:
好name, address, salary
不好nam, addr, sal
1.1.5 用于循环迭代的变量例外:允许使用单个字母的变量,例如i
for ( int i = 0; i < count; i++ )
{
...
}
1.1.6 变量名中不使用下划线 (_) 。
1.1.7 名称空间需按照标准的模式命名,例如公司名.产品名,把微软的名称空间放在前面,随后是自定义的名称空间,最后是第三方的名称空间。
1.1.8 文件名要和类名匹配
例如,对于类HelloWorld, 相应的文件名应为 helloworld.cs (或, helloworld.vb)
1.1.9 缩进和间隔
缩进用 TAB,不用空格。
1.1.10 注释需和代码对齐。
花括弧 ( {} ) 需和括号外的代码对齐。
用一个空行来分开代码的逻辑分组。
bool SayHello (string name)
{
string fullMessage = "Hello " + name;
DateTime currentTime = DateTime.Now;
string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
MessageBox.Show ( message );
if ( ... )
{
// Do something
// ...
return false;
}
return true;
}
1.1.11 在一个类中,各个方法需用一空行,也只能是一行分开。
1.1.12 花括弧需独立一行,而不像if, for 等可以跟括号在同一行。即使只有一行的if语句也用花括弧。
好:
if ( ... )
{
// Do something
}
不好:
if ( ... ) {
// Do something
}
1.1.13 空格要求:在每个运算符的前后都空一格;
方法调用的括号左右没有空格;
if、while、for和后面的左圆括号之间有一个空格,但是左圆括号之后没有空格;
分号左边没有空格
(这个例子用“□”表示空格)
好:
if□(showResult□==□true)
{
string□message□=□" the time is : "□+□currentTime.ToShortTimeString();
MessageBox.Show(message);
for□(int□i□=□0;□i□<□10;□i□++□)
{
//
}
}
不好:
if(showResult==true)
{
string message = " the time is : " + currentTime.ToShortTimeString();
MessageBox.Show□(□message□);
for(int i= 0;i<10;i++)
{
//
}
}
1.1.14 不要手工编辑Visual Studio.Net自动产生的代码;
1.1.15 不用提供public或protected成员变量,而是使用属性。
1.1.16 避免显式类型转换。使用as算法防护性地转换类型。
Dog dog = new GermanShepherd();
GermanShepherd shepherd = dog as GermanShepherd;
if(shepherd != null)
{...}
1.1.17 总是使用从0开始的数组。
1.1.18 类成员有委托时,调用前始终检查委托是否为空。
public class MySource
{
public event EventHandler MyEvent;
public void FireEvent()
{
EventHandler temp = MyEvent;
if (temp != null)
{
temp(this,EventArgs.Empty);
}
}
}
1.1.19 总是使用一个for循环显式地初始化一个引用类型的数组。
public class MyClass
{}
MyClass[] array = new MyClass[100];
for(int index = 0; index < array.Length; index++)
{
array[index] = new MyClass();
}
1.1.20 避免在布尔条件语句中调用函数。赋值到局部变量并检查它们的值。
bool IsEverythingOK()
{...}
//不好:
if(IsEverythingOK())
{...}
//好:
bool ok = IsEverythingOK();
if (ok)
{
...
}
1.1.21 避免对只读变量使用const修饰符。在此情况下,采用readonly修饰符。
public class MyClass
{
public readonly int Number;
public MyClass(int someValue)
{
Number = someValue;
}
public const int DaysInWeek = 7;
}
1.1.22 避免使用大文件。
如果一个文件里的代码超过300~400行,必须考虑将代码分开到不同类中。避免写太长的方法。一个典型的方法代码在1~25行之间。如果一个方法发代码超过25行,应该考虑将其分解为不同的方法。避免一个方法的参数超过5个,必要时使用对象(含多个属性)作为参数。(这一条不强求)
1.1.23 方法名需能看出它作什么。别使用会引起误解的名字。如果名字一目了然,就无需用文档来解释方法的功能了。
好:
void SavePhoneNumber ( string phoneNumber )
{
// Save the phone number.
}
不好:
// This method will save the phone number.
void SaveData ( string phoneNumber )
{
// Save the phone number.
}
1.1.24 一个方法只完成一个任务。不要把多个任务组合到一个方法中,即使那些任务非常小。
好:
// Save the address.
SaveAddress ( address );
// Send an email to the supervisor to inform that the address is updated.
SendEmail ( address, email );
void SaveAddress ( string address )
{
// Save the address.
// ...
}
void SendEmail ( string address, string email )
{
// Send an email to inform the supervisor that the address is changed.
// ...
}
不好:
// Save address and send an email to the supervisor to inform that the address is updated.
SaveAddress ( address, email );
void SaveAddress ( string address, string email )
{
// Job 1.
// Save the address.
// ...
// Job 2.
// Send an email to inform the supervisor that the address is changed.
// ...
}
1.1.25 使用C#的特有类型,而不是System命名空间中定义的别名类型。
好:
int age;
string name;
object contactInfo;
不好:
Int16 age;
String name;
Object contactInfo;
1.1.26 别在程序中使用固定数值,用常量代替。常量都用完全大写单词。
1.1.27 别用字符串常数。用资源文件。
1.1.28 避免使用很多成员变量。
声明局部变量,并传递给方法。不要在方法间共享成员变量。如果在几个方法间共享一个成员变量,那就很难知道是哪个方法在什么时候修改了它的值。
1.1.29 必要时使用enum 。别用数字或字符串来指示离散值。
好:
enum MailType
{
Html,
PlainText,
Attachment
}
void SendMail (string message, MailType mailType)
{
switch (mailType)
{
case MailType.Html:
// Do something
break;
case MailType.PlainText:
// Do something
break;
case MailType.Attachment:
// Do something
break;
default:
// Do something
break;
}
}
不好:
void SendMail (string message, string mailType)
{
switch ( mailType )
{
case "Html":
// Do something
break;
case "PlainText":
// Do something
break;
case "Attachment":
// Do something
break;
default:
// Do something
break;
}
}
1.1.30 别把成员变量声明为 public 或 protected。都声明为 private 而使用 public/protected 的Properties.
1.1.31 不在代码中使用具体的路径和驱动器名。 使用相对路径,并使路径可编程。
永远别设想你的代码是在“C:”盘运行。你不会知道,一些用户在网络或“Z:”盘运行程序。
1.1.32 应用程序启动时作些“自检”并确保所需文件和附件在指定的位置。必要时检查数据库连接。出现任何问题给用户一个友好的提示。
1.1.33 如果需要的配置文件找不到,应用程序需能自己创建使用默认值的一份。如果在配置文件中发现错误值,应用程序要抛出错误,给出提示消息告诉用户正确值。
1.1.34 错误消息需能帮助用户解决问题。永远别用像"应用程序出错", "发现一个错误" 等错误消息。而应给出像 "更新数据库失败。请确保登陆id和密码正确。" 的具体消息。
1.1.35 显示错误消息时,除了说哪里错了,还应提示用户如何解决问题。不要用 像 "登录失败。"这样的,要提示用户怎么做:"登录失败。请确保登录名和密码正确。"
1.1.36 显示给用户的消息要简短而友好。但要把所有可能的信息都记录下来,以助诊断问题。
1.1.37 文件头注释要求:
/// <summary>
/// 登录验证WebService
/// </summary>
/// <history>
/// <date>2004-02-25</date>
/// <programmer>张三</programmer>
/// <document>第一次做成,参考《登录验证详细设计书》3.2.1WebService</document>
/// <date>2004-11-22</date>
/// <programmer>李四</programmer>
/// <document>修正一个安全漏洞,参考《系统安全设计书》1.2.5</document>
/// </history>
1.1.38 方法头注释要求:
/// <summary>
/// 从数据库验证用户名和密码
/// </summary>
/// <param name = "username">用户名</param>
/// <param name = "password">密码</param>
/// <returns>true表示成功,false表示失败</returns >
/// <history>
/// <date>2004-02-25</date>
/// <programmer>张三</programmer>
/// <document>第一次做成,参考《登录验证详细设计书》3.2.1WebService</document>
/// </history>
private bool CheckUserValidation(string username, string password)
{
…
}
如果使用了复杂的算法,应为程序配备良好的文档和充分的注释。在文件头或者方法头增加算法描述。
在软件版本变更或者修改其他同事的代码时候,如果需要删除,应该用注释,而不是直接删除;如果需要修改,应该先注释原始的代码,然后增加新代码;新增代码也必须注释;
同一版本debug自己的代码发现错误,则直接修改,不需要注释;
例如:原始代码
private bool CheckUserValidation(string username, string password)
{
string sqlText = string.Format(“Select top 1 * from tUser where fLoginName = {0}”, username);
MessageBox.Show(sqlText);
…
}
修改后的代码
private bool CheckUserValidation(string username, string password)
{
// <modify>
// <date>2004-11-22</date>
// <programmer>李四</programmer>
// <reason>
// 原始代码仅仅比较用户名,没有考虑密码。参考《登录验证详细设计书》3.2.1
// </reason>
// <original>
// </original>
// <new>
string sqlText = string.Format(“Select top 1 * from tUser where fLoginName = {0} and fPassword = {1}”, username, password);
// </new>
// </modify>
// <delete>
// <date>2004-11-22</date>
// <programmer>李四</programmer>
// <reason>正式版本中不需要在服务器上提示消息框。</reason>
// <original>
// </original>
// </delete>
…
// <add>
// <date>2004-11-22</date>
// <programmer>李四</programmer>
// <reason>……</reason>
some new codes
// </add>
}
1.1.39 异常处理
不要捕捉了异常却什么也不做。如果隐藏了一个异常,你将永远不知道异常到底发生了没有。
发生异常时,给出友好的消息给用户,但要精确记录错误的所有可能细节,包括发生的时间,和相关方法,类名等。
先捕捉特定的异常,后捕捉一般的异常。
例如:
private void ReadFromFile ( string fileName )
{
try
{
// read from file.
}
catch (FileIOException ex)
{
// log error.
// re-throw exception depending on your case.
throw ex;
}
catch (Exception e)
{
// Catching general exception
// log error.
throw e
}
}
在开发版本中捕获一般异常,写入日志,然后抛出一般异常,让程序崩溃。这将帮助你在开发周期发现大多数的错误。
不必每个方法都用try-catch。当特定的异常可能发生时才使用。比如,当你写文件时,处理异常FileIOException.
别写太大的 try-catch 模块。如果需要,为每个执行的任务编写单独的 try-catch 模块。 这将帮你找出哪一段代码产生异常,并给用户发出特定的错误消息
如果应用程序需要,可以编写自己的异常类。自定义异常不应从基类SystemException派生,而要继承于. IApplicationException。