C#編碼規範
1 規範目的 ……………………………………………………… 3
2 適用範圍 ……………………………………………………… 3
3 代碼註釋 ……………………………………………………… 3
3.1 代碼註釋約定............................................ 3
3.2 模塊頭部註釋規範...................................... 3
3.3 方法註釋規範............................................. 4
3.4 代碼行註釋規範.......................................... 6
3.5 變量註釋規範............................................. 7
4 命名規則 ……………………………………………………… 8
4.1 命名的基本約定.......................................... 8
4.2 各種標示符類型的基本約定......................... 9
4.3 組件名稱縮寫列表....................................... 10
5 其它規範 ……………………………………………………… 11
5.1 編程風格.................................................. 11
5.2 資源釋放.................................................. 13
5.3 錯誤處理.................................................. 13
5.4 其它......................................................... 14
1 規範目的
- 一個軟件的生命週期中,80%的花費在於維護;
- 幾乎沒有任何一個軟件,在其整個生命週期中,均由最初的開發人員來維護;
- 編碼規範可以改善軟件的可讀性,可以讓程序員儘快而徹底地理解新的代碼。爲了執行規範,每個軟件開發人員必須一致遵守編碼規範;
- 使用統一編碼規範的主要原因,是使應用程序的結構和編碼風格標準化,以便於閱讀和理解這段代碼;
- 好的編碼約定可使源代碼嚴謹、可讀性強且意義清楚,與其它語言約定相一致,並且儘可能的直觀。
2 適用範圍
- 本規範主要以C#爲開發語言的規範,爲鮑亮實驗室的原則性規範;
- 由於本規範是爲撰寫程序而設計,所以適用於一切有關程序撰寫的工作事項。對於具體的每個項目,可能需要對之進行裁剪和補存。
- 適用人員:軟件工程專業的學生;
- 適用產品:以C#編寫的程序。
3 代碼註釋
3.1 代碼註釋約定
- 所有的方法和函數都應該以描述這段代碼的功能的一段簡明註釋開始(方法是幹什麼)。這種描述不應該包括執行過程細節(它是怎麼做的),因爲這常常是隨時間而變的,而且這種描述會導致不必要的註釋維護工作,甚至更糟—成爲錯誤的註釋。代碼本身和必要的嵌入註釋將描述實現方法。
- 當參數的功能不明顯且當過程希望參數在一個特定的範圍內時,也應描述傳遞給過程的參數。被過程改變的函數返回值和全局變量,特別是通過引用參數的那些,也必須在每個過程的起始處描述它們。
3.2 模塊頭部註釋規範
以一個物理文件爲單元的都需要有模塊頭部註釋規範,例如:C#中的.cs文件
用於每個模塊開頭的說明,主要包括:(粗體字爲必需部分,其餘爲可選部分)
- 文件名稱(File Name): 此文件的名稱
- 功能描述(Description): 此模塊的功能描述與大概流程說明
- 數據表(Tables): 所用到的數據表,視圖,存儲過程的說明,如關係比較複雜,則應說明哪些是可擦寫的,哪些表爲只讀的。
- 作者(Author):
- 日期(Create Date):
- 參考文檔(Reference)(可選): 該檔所對應的分析文檔,設計文檔。
- 引用(Using) (可選)﹕ 開發的系統中引用其它系統的Dll、對象時,要列出其對應的出處,是否與系統有關﹙不清楚的可以不寫﹚,以方便製作安裝檔。
- 修改記錄(Revision History):若檔案的所有者改變,則需要有修改人員的名字、修改日期及修改理由。
- 分割符:*************************** (前後都要)
示例如下:
3.3 方法註釋規範
1> C# 提供一種機制,使程序員可以使用含有XML 文本的特殊註釋語法爲他們的代碼編寫文檔。在源代碼文件中,具有某種格式的註釋可用於指導某個工具根 據這些註釋和它們後面的源代碼元素生成XML。具體應用當中,類、接口、屬性、方法必須有<Summary>節,另外方法如果有參數及返回值,則必須有 <Param>及<Returns>節。示例如下:
/// <summary>
/// …
/// </summary>
/// <param name=””></param>
/// <returns></returns>
2> 事件不需要頭註解,但包含複雜處理時(如:循環/數據庫操作/複雜邏輯等),應分割成單一處理函數,事件再調用函數。
3> 所有的方法必須在其定義前增加方法註釋。
4> 方法註釋採用 /// 形式自動產生XML標籤格式的註釋。
標記 |
說明 |
備註 |
<c> |
提供了一種將說明中的文本標記爲代碼的方法 |
|
<code> |
提供了一種將多行指示爲代碼的方法 |
|
<example> |
可以指定使用方法或其他庫成員的示例。一般情況下,這將涉及到 <code> 標記的使用。 |
|
<exception> |
對可從當前編譯環境中獲取的異常的引用。 |
|
<include> |
得以引用描述源代碼中類型和成員的另一文件中的註釋。 |
|
<list> |
用於定義表或定義列表中的標題行。 |
|
<para> |
用於諸如<summary>、<remarks> 或 <returns> 等標記內,使您得以將結構添加到文本中。 |
|
<param> |
應當用於方法聲明的註釋中,以描述方法的一個參數。 |
|
<paramref> |
提供了一種指示詞爲參數的方法。 |
|
<permission> |
得以將成員的訪問記入文檔。 |
|
<remarks> |
用於添加有關某個類型的信息,從而補充由 <summary> 所指定的信息。 |
|
<returns> |
應當用於方法聲明的註釋,以描述返回值。 |
|
<see> |
得以從文本內指定鏈接。 |
|
<seealso> |
對可以通過當前編譯環境進行調用的成員或字段的引用。 |
|
<summary> |
應當用於描述類型或類型成員。 |
|
<value> |
得以描述屬性。 |
|
示例圖如下:
5> 在公用類庫中的公用方法需要在一般方法的註釋後添加作者、日期及修改記錄信息,統一採用XML標籤的格式加註,標籤如下:
<Author></Author> 作者
<CreateDate></CreateDate> 建立日期
<RevisionHistory> 修改記錄
<ModifyBy></ModifyBy> 修改作者
<ModifyDate></ModifyDate> 修改日期
<ModifyReason></ModifyReason> 修改理由
<ModifyBy></ModifyBy> 修改作者
<ModifyDate></ModifyDate> 修改日期
<ModifyReason></ModifyReason> 修改理由
<ModifyBy></ModifyBy> 修改作者
<ModifyDate></ModifyDate> 修改日期
<ModifyReason></ModifyReason> 修改理由
</RevisionHistory>
<LastModifyDate></LastModifyDate> 最後修改日期
6> 一個代碼文件如果是由一人編寫,則此代碼文件中的方法無需作者信息,非代碼文件作者在此文件中添加方法時必須要添加作者、日期等註釋。
7> 修改任何方法,必須要添加修改記錄的註釋。
3.4 代碼行註釋規範
1> 如果處理某一個功能需要很多行代碼實現,並且有很多邏輯結構塊,類似此種代碼應該在代碼開始前添加註釋,說明此塊代碼的處理思路及注意事項等
2> 註釋從新行增加,與代碼開始處左對齊
3> 雙斜線與註釋之間以空格分開,示例圖如下所示:
3.5 變量註釋規範
1> 定義變量時需添加變量註釋,用以說明變量的用途。
2> Class級變量應以採用 /// 形式自動產生XML標籤格式的註釋,示例圖如下所示:
3> 方法級的變量註釋可以放在變量聲明語句的後面,與前後行變量聲明的註釋左對齊,註釋與代碼間以Tab隔開。
4 命名規則
4.1 命名的基本約定
1> 要使用可以準確說明變量/字段/類的完整的英文描述符,如firstName。對一些作用顯而易見的變量可以採用簡單的命名,如在循環裏的遞增(減)變量就可以 被命名爲 “i”。
2> 要儘量採用項目所涉及領域的術語。
3> 要採用大小寫混合,提高名字的可讀性。爲區分一個標識符中的多個單詞,把標識符中的每個單詞的首字母大寫。不採用下劃線作分隔字符的寫法。
有兩種適合的書寫方法,適應於不同類型的標識符:
PasalCasing:標識符的第一個單詞的字母大寫;
camelCasing:標識符的第一個單詞的字母小寫。
4> 下表描述了不同類型標識符的大小寫規則:
標識符 |
大小寫 |
示例 |
命名空間 |
Pascal |
namespace Com.Techstar.ProductionCenter |
類型 |
Pascal |
public class DevsList |
接口 |
Pascal |
public interface ITableModel |
方法 |
Pascal |
public void UpdateData() |
屬性 |
Pascal |
Public int Length{…} |
事件 |
Pascal |
public event EventHandler Changed; |
私有字段 |
Camel |
private string fieldName; |
非私有字段 |
Pascal |
public string FieldName; |
枚舉值 |
Pascal |
FileMode{Append} |
參數 |
Camel |
public void UpdateData(string fieldName) |
局部變量 |
Camel |
string fieldName; |
5> 避免使用縮寫,如果一定要使用,就謹慎使用。同時,應該保留一個標準縮寫的列表,並且在使用時保持一致。
6> 對常見縮略詞,兩個字母的縮寫要採用統一大小寫的方式(示例:ioStream, getIOStream);多字母縮寫採用首字母大寫,其他字母小寫的方式(示例: getHtmlTag);
7> 避免使用長名字(最好不超過 15 個字母)。
8> 避免使用相似或者僅在大小寫上有區別的名字。
4.2 各種標示符類型的命名約定
1> 程序集命名
實驗室名稱(Lab)+ 項目名稱 + 模塊名稱(可選),例如:
中心服務器程序集:Lab.SeverCenter;
中心服務器業務邏輯程序集:Lab.SeverCenter.Business;
2> 命名空間命名
採用和程序集命名相同的方式:實驗室名稱(Lab)+ 項目名稱 + 模塊名稱。 另外,一般情況下建議命名空間和目錄結構相同。例如:
中心服務器:Lab.SeverCenter;
中心服務器下的用戶控件:Lab.SeverCenter.UserControl;
中心服務器業務邏輯:Lab.SeverCenter.Business;
中心服務器數據訪問:Lab.SeverCenter.Data;
3> 程序集和DLL
l 大多數情況下,程序集包含全部或部分可重用庫,且它包含在單個動態鏈接庫(DLL) 中。
l 一個程序集可拆分到多個DLL 中,但這非常少見,在此準則中也沒有說明。
l 程序集和DLL 是庫的物理組織,而命名空間是邏輯組織,其構成應與程序集的組織無關。
l 命名空間可以且經常跨越多個程序集。可以考慮如下模式命名DLL:
<Company>.<Component>.dll
例:Lab.SeverCenter.dll
4> 類和接口命名
l 類的名字要用名詞;
l 避免使用單詞的縮寫,除非它的縮寫已經廣爲人知,如HTTP。
l 接口的名字要以字母I開頭。保證對接口的標準實現名字只相差一個“I”前綴,例如對IComponent接口的標準實現爲Component;
l 泛型類型參數的命名:命名要爲T或者以T開頭的描述性名字,例如:
public class List<T>
public class MyClass<Tsession>
l 對同一項目的不同命名空間中的類,命名避免重複。避免引用時的衝突和混淆;
5> 方法命名
l 第一個單詞一般是動詞;
l 如果方法返回一個成員變量的值,方法名一般爲Get+成員變量名,如若返回的值 是bool變量,一般以Is作爲前綴。另外,如果必要,考慮用屬性來替代方法;
l 如果方法修改一個成員變量的值,方法名一般爲:Set + 成員變量名。同上,考慮 用屬性來替代方法。
6> 變量命名
l 按照使用範圍來分,我們代碼中的變量的基本上有以下幾種類型,類的公有變量;類的私有變量(受保護同公有);方法的參數變量;方法內部使用的局部變量。 這些變量的命名規則基本相同,見標識符大小寫對照表。區別如下:
a) 類的公有變量按通常的方式命名,無特殊要求;
b) 類的私有變量採用兩種方式均可:採用加“m”前綴,例如mWorkerName;
c) 方法的參數變量採用camalString,例如workerName;
l 方法內部的局部變量採用camalString,例如workerName。
l 不要用_或&作爲第一個字母;
l 儘量要使用短而且具有意義的單詞;
l 單字符的變量名一般只用於生命期非常短暫的變量:i,j,k,m,n一般用於integer;c,d,e 一般用於characters;s用於string
l 如果變量是集合,則變量名要用複數。例如表格的行數,命名應爲:RowsCount;
l 命名組件要採用匈牙利命名法,所有前綴均應遵循同一個組件名稱縮寫列表
4.3 組件名稱縮寫列表
縮寫的基本原則是取組件類名各單詞的第一個字母,如果只有一個單詞,則去掉其中的元音,留下輔音。縮寫全部爲小寫。
組件類型 |
縮寫 |
例子 |
Label |
Lbl |
lblNote |
TextBox |
Txt |
txtName |
Button |
Btn |
btnOK |
ImageButton |
Ib |
ibOK |
LinkButton |
Lb |
lbJump |
HyperLink |
Hl |
hlJump |
DropDownList |
Ddl |
ddlList |
CheckBox |
Cb |
cbChoice |
CheckBoxList |
Cbl |
cblGroup |
RadioButton |
Rb |
rbChoice |
RadioButtonList |
Rbl |
rblGroup |
Image |
Img |
imgBeauty |
Panel |
Pnl |
pnlTree |
TreeView |
Tv |
tvUnit |
WebComTable |
Wct |
wctBasic |
ImageDateTimeInput |
Dti |
dtiStart |
ComboBox |
Cb |
cbList |
MyImageButton |
Mib |
mibOK |
WebComm.TreeView |
Tv |
tvUnit |
PageBar |
Pb |
pbMaster |
5 其它規範
5.1 編程風格
1> 變量聲明:
爲了保持更好的閱讀習慣,請不要把多個變量聲明寫在一行中,即一行只聲明一個變量。
例如:
String strTest1, strTest2;
應寫成:
String strTest1;
String strTest2;
2> 代碼縮進:
l 一致的代碼縮進風格,有利於代碼的結構層次的表達,使代碼更容易閱讀和傳閱;
l 代碼縮進使用Tab鍵實現,最好不要使用空格,爲保證在不同機器上使代碼縮進保持一致,特此規定C#的Tab鍵寬度爲4個字符,設定界面如下(工具–選項):
l 避免方法中有超過5個參數的情況,一般以2,3個爲宜。如果超過了,則應使用struct來傳遞多個參數。
l 爲了更容易閱讀,代碼行請不要太長,最好的寬度是屏幕寬度(根據不同的顯示分辯率其可見寬度也不同)。請不要超過您正在使用的屏幕寬度。(每行代碼不要 超過80個字符。)
l 程序中不應使用goto語句。
l 在switch語句中總是要default子句來顯示信息。
l 方法參數多於8個時採用結構體或類方式傳遞
l 操作符/運算符左右空一個半角空格
l 所有塊的{}號分別放置一行,並嵌套對齊,不要放在同一行上
3> 空白:
l 空行將邏輯相關的代碼段分隔開,以提高可讀性。
l 下列情況應該總是使用兩個空行:
a) 一個源文件的兩個片段(section)之間。
b) 類聲明和接口聲明之間。
l 下列情況應該總是使用一個空行:
a) 兩個方法之間。
b) 方法內的局部變量和方法的第一條語句之間。
c) 塊註釋(參見"5.1.1")或單行註釋(參見"5.1.2")之前。
d) 一個方法內的兩個邏輯段之間,用以提高可讀性。
l 下列情況應該總是使用空格:
a) 空白應該位於參數列表中逗號的後面,如:
void UpdateData(int a, int b)
b) 所有的二元運算符,除了".",應該使用空格將之與操作數分開。一元操作符和操作數之間不因該加空格,比如:負號("-")、自增("++")和自減("--")。例 如:
a += c + d;
d++;
c) for 語句中的表達式應該被空格分開,例如:
for (expr1; expr2; expr3)
d) 強制轉型後應該跟一個空格,例如:
char c;
int a = 1;
c = (char) a;
5.2 資源釋放
所有外部資源都必須顯式釋放。例如:數據庫連接對象、IO對象等。
5.3 錯誤處理
1> 不要“捕捉了異常卻什麼也不做“。如果隱藏了一個異常,你將永遠不知道異常到底發生了沒有。
2> 發生異常時,給出友好的消息給用戶,但要精確記錄錯誤的所有可能細節,包括髮生的時間,和相關方法,類名等。
3> 只捕捉特定的異常,而不是一般的異常。
正確做法:
錯誤做法:
5.4 其它
1> 一個方法只完成一個任務。不要把多個任務組合到一個方法中,即使那些任務非常小。
2> 使用C#的特有類型,而不是System命名空間中定義的別名類型。
3> 別在程序中使用固定數值,用常量代替。
4> 避免使用很多成員變量。聲明局部變量,並傳遞給方法。不要在方法間共享成員變量。如果在幾個方法間共享一個成員變量,那就很難知道是哪個方法在什麼 時候修改了它的值。
5> 別把成員變量聲明爲 public 或 protected。都聲明爲 private 而使用 public/protected 的屬性
6> 不在代碼中使用具體的路徑和驅動器名。 使用相對路徑,並使路徑可編程。
7> 應用程序啓動時作些“自檢”並確保所需文件和附件在指定的位置。必要時檢查數據庫連接。出現任何問題給用戶一個友好的提示。
8> 如果需要的配置文件找不到,應用程序需能自己創建使用默認值的一份。
9> 如果在配置文件中發現錯誤值,應用程序要拋出錯誤,給出提示消息告訴用戶正確值。
10> DataColumn取其列時要用字段名,不要用索引號。
例: 正確DataColumn[“Name”]
不好 DataColumn[0]
11> 在一個類中,字段定義全部統一放在class的頭部、所有方法或屬性的前面。
12> 在一個類中,所有的屬性全部定義在一個屬性塊中: