1. 引言
本文是一套面向C# programmer 和C# developer 進(jìn)行開(kāi)發(fā)所應(yīng)遵循的開(kāi)發(fā)規(guī)范。
按照此規(guī)范來(lái)開(kāi)發(fā)C#程序可帶來(lái)以下益處:
· 代碼的編寫(xiě)保持一致性,
· 提高代碼的可讀性和可維護(hù)性,
· 在團(tuán)隊(duì)開(kāi)發(fā)一個(gè)項(xiàng)目的情況下,程序員之間可代碼共享
· 易于代碼的回顧,
本規(guī)范是初版,只適用于一般情況的通用規(guī)范,并不能覆蓋所有的情況。
2. 文件組織
2.1 C# 源文件
類名或文件名要簡(jiǎn)短,不要超過(guò)2000LOC,將代碼分割開(kāi),使結(jié)構(gòu)清晰。將每個(gè)類放在一個(gè)單獨(dú)的文件中,使用類名來(lái)命名文件名(當(dāng)然擴(kuò)展名是.cs)。這種約定會(huì)使大家工作更簡(jiǎn)單。
2.2 目錄設(shè)計(jì)
為每一個(gè)命名空間創(chuàng)建一個(gè)目錄。(用MyProject/TestSuite/TestTier作為MyProject.TestSuite.TestTier的路徑,而不用帶點(diǎn)的命名空間名做路徑)這樣可以更容易地將命名空間映射到目錄層次劃分。
3. 縮進(jìn)
3.1 換行
當(dāng)一個(gè)表達(dá)式超過(guò)一行時(shí),根據(jù)這些通用原則進(jìn)行處理:
· 在逗號(hào)后換行。
· 在操作符后換行。
· 在高層換行而不要在低層處換行。
· 折行后對(duì)齊上一行語(yǔ)句同一層的表達(dá)式起始位置。
方法調(diào)用換行示例:
- longMethodCall(expr1, expr2,
- expr3, expr4, expr5);
算術(shù)表達(dá)式換行示例:
推薦:
- var = a * b / (c - g + f) +
- 4 * z;
不好的格式——應(yīng)避免:
- var = a * b / (c - g +
- f) + 4 * z;
推薦使用第一種方法,因?yàn)槭窃诶ㄌ?hào)表達(dá)式之外折行(高層次折行原則)。注意要用制表符到縮進(jìn)的位置,然后用用空格到折行的位置。在我們的例子中是:
- > var = a * b / (c - g + f) +
- > ......4 * z;
'>'表示是制表符,'.'表示是空格符。(制表符后是空白是用制表符縮進(jìn))。一個(gè)好的編碼習(xí)慣就是在所用的編輯器中顯示制表符和空格符。
3.2 空白
利用空格進(jìn)行縮進(jìn)從未有過(guò)統(tǒng)一的標(biāo)準(zhǔn)。一些人喜歡用兩個(gè)空格,一些人喜歡用四個(gè)空格而還有一些人喜歡用八個(gè)空格,甚至有的人喜歡用更多的空格。好的做法是用制表符。制表符有一些優(yōu)點(diǎn):
· 每個(gè)人都可以設(shè)置他們自己喜歡的縮進(jìn)層級(jí)。
· 它僅僅是1個(gè)字符而不是2,4,8等等,因此它將減少輸入(甚至因?yàn)樽詣?dòng)縮進(jìn),有時(shí)你不得不手工設(shè)置縮進(jìn)或取消設(shè)置,等等諸如此類的操作)。
· 如果你想增加或減少縮進(jìn),可以標(biāo)記一塊,使用Tab增加縮進(jìn)層級(jí)而用Shift-Tab減少縮進(jìn)層級(jí)。這幾乎對(duì)于任何文本編輯器都是適用的。
這里,我們定義制表符為標(biāo)準(zhǔn)縮進(jìn)符。
不要用空格縮進(jìn)—用制表符!
4. 注釋
4.1 塊注釋
塊注釋通常應(yīng)該是被避免的。推薦使用///注釋作為C#的標(biāo)準(zhǔn)聲明。如果希望用塊注釋時(shí)你應(yīng)該用以下風(fēng)格:
- /* Line 1
- * Line 2
- * Line 3
- */
因?yàn)闃涌梢詾樽x者將注釋塊與代碼塊區(qū)分開(kāi)。雖然并不提倡使用C風(fēng)格的單行注釋,但你仍然可以使用。一旦用這種方式,那么在注釋行后應(yīng)有斷行,因?yàn)楹茈y看清在同一行中前面有注釋的代碼:
- /* blah blah blah */
塊注釋在極少情況下是有用的。通常塊注釋用于注釋掉大的代碼段。
4.2 單行注釋
你應(yīng)該用//注釋風(fēng)格“注釋掉”代碼(快捷鍵,Alt+/)。它也可以被用于代碼的注釋部分。
單行注釋被用于代碼說(shuō)明時(shí)必須縮進(jìn)到相應(yīng)的編進(jìn)層級(jí)。注釋掉的代碼應(yīng)該放在第一行被注釋掉以使注釋掉的代碼更容易看清。
一條經(jīng)驗(yàn),注釋的長(zhǎng)度不應(yīng)該超過(guò)被解釋代碼的長(zhǎng)度太長(zhǎng),因?yàn)檫@表示代碼過(guò)于復(fù)雜,有潛在的bug。
4.3 文件注釋
在.net 框架,Microsoft 已經(jīng)介紹了一個(gè)基于XML 注釋的文件。這些文件是包括XML 標(biāo)簽的正規(guī)的單行的C#注釋。他們遵循單行注釋的模式:
- /// <summary>
- /// This class...
- /// </summary>
多行XML 注釋遵循這種模式:
- /// <exception cref=”BogusException”>
- /// This exception gets thrown as soon as a
- /// Bogus flag gets set.
- /// </exception>
為了被認(rèn)作是XML注釋行,所有的行都必須用三個(gè)反斜線開(kāi)始。標(biāo)簽有以下兩類:
· 文件說(shuō)明項(xiàng)
· 格式/參考
第一類包括像<summary>, <param> or <exception>的標(biāo)簽。描述一個(gè)程序的API元素的這些文檔說(shuō)明項(xiàng)必須寫(xiě)清楚以方便其他程序員。如上面的多行注釋示例所示,這些標(biāo)簽通常帶有名稱或cref屬性。編譯器會(huì)檢查這些屬性,所以它們必須是有效、正確的。第二類用諸如<code>, <list> or <para>標(biāo)簽,用于控制備注說(shuō)明的布局。
文件可以用‘文件’菜單中的‘創(chuàng)建’菜單產(chǎn)生。文件以HTML格式產(chǎn)生。
5. 聲明
5.1 每行的聲明數(shù)
推薦每行只有一個(gè)聲明,因?yàn)樗梢苑奖阕⑨尅?/p>
- int level; // indentation level
- int size; // size of table
當(dāng)聲明變量時(shí),不要把多個(gè)變量或不同類型的變量放在同一行,例如:
- int a, b; //What is 'a'? What does 'b' stand for?
上面的例子也顯示了變量名不明顯的缺陷。當(dāng)命名變量時(shí)要清晰。
5.2 初始化
局部變量一旦被聲明就要初始化。例如:
- string name = myObject.Name;
或
- int val = time.Hours;
注意:如果你初始化一個(gè)dialog,設(shè)計(jì)使用using語(yǔ)句:
- using (OpenFileDialog openFileDialog = new OpenFileDialog()) {
- ...
- }
5.3 類和接口聲明
當(dāng)編寫(xiě)C#類和接口時(shí),應(yīng)遵循以下格式化規(guī)則:
· 在方法名和圓括號(hào)“(”開(kāi)始它的參數(shù)列表之間不要使用空格。
· 在聲明語(yǔ)句的下一行以大括號(hào)"{"標(biāo)志開(kāi)始。
· 以"}"結(jié)束,通過(guò)它自身的縮進(jìn)與相應(yīng)的開(kāi)始標(biāo)志匹配。
例如:
- Class MySample : MyClass, IMyInterface
- {
- int myInt;
- public MySample(int myInt)
- {
- this.myInt = myInt ;
- }
- void Inc()
- {
- ++myInt;
- }
- void EmptyMethod()
- {
- }
- }
對(duì)于一個(gè)大括號(hào)的位置參考10.1部分。
6. 語(yǔ)句
6.1 簡(jiǎn)單語(yǔ)句
每行都應(yīng)該只包含一條語(yǔ)句。
6.2 返回語(yǔ)句
一個(gè)返回語(yǔ)句不要用最外圍圓括號(hào)。不用:
return (n * (n + 1) / 2);
用: return n * (n + 1) / 2;
6.3 If, if-else, if else-if else 語(yǔ)句
if, if-else and if else-if else 語(yǔ)句看起來(lái)應(yīng)該像這樣:
- if (condition) {
- DoSomething();
- ...
- }
- if (condition) {
- DoSomething();
- ...
- } else {
- DoSomethingOther();
- ...
- }
- if (condition) {
- DoSomething();
- ...
- } else if (condition) {
- DoSomethingOther();
- ...
- } else {
- DoSomethingOtherAgain();
- ...
- }
6.4 for / foreach 語(yǔ)句
一個(gè)for語(yǔ)句應(yīng)該如下形式:
- for (int i = 0; i < 5; ++i) {
- ...
- }
或者放置一行(考慮用一個(gè)while語(yǔ)句代替)
- for (initialization; condition; update) ;
foreach語(yǔ)句應(yīng)該像下面所示 :
- foreach (int i in IntList) {
- ...
- }
注意:在一個(gè)循環(huán)中,即使只有一個(gè)語(yǔ)句通常也用括弧括起來(lái)。
6.5 While/do-while 語(yǔ)句
一個(gè)while語(yǔ)句應(yīng)該寫(xiě)成如下形式:
- while (condition) {
- ...
- }
一個(gè)空while語(yǔ)句應(yīng)該是以下格式:
while (condition) ;
一個(gè)do-while語(yǔ)句應(yīng)該是如下格式:
- do
- {
- ...
- } while (condition);
6.6 Switch 語(yǔ)句
一個(gè)switch語(yǔ)句應(yīng)該如下格式:
- switch (condition) {
- case A:
- ...
- break;
- case B:
- ...
- break;
- default:
- ...
- break;
- }
6.7 Try-catch 語(yǔ)句
一個(gè)try-catch statement語(yǔ)句應(yīng)該遵循以下格式:
- try {
- ...
- } catch (Exception) {}
- or
- try {
- ...
- } catch (Exception e) {
- ...
- }
- or
- try {
- ...
- } catch (Exception e) {
- ...
- } finally {
- ...
- }
7. 空白
7.1 空行
空行提高可讀性。它們分開(kāi)那些邏輯上自身相關(guān)聯(lián)的代碼塊。兩行空格行應(yīng)該用于以下之間:
· 一個(gè)源文件的邏輯段。
· 類和接口定義(每個(gè)文件只定義一個(gè)類或接口以避免這種情況)。
一個(gè)空格行應(yīng)該總是被用于以下之間:
· 方法
· 屬性
· 一個(gè)方法中的局部變量和它的第一條語(yǔ)句
· 一個(gè)方法中的邏輯段為了提高可讀性。注意空白行必須被縮進(jìn)因?yàn)樗鼈儼ㄒ粭l語(yǔ)句這使得插入這些行更容易。
7.2 內(nèi)部空格
在一個(gè)逗號(hào)或一個(gè)分號(hào)之后應(yīng)該由一個(gè)空格,例如:
- TestMethod(a, b, c); 不要用: TestMethod(a,b,c)
或
- TestMethod( a, b, c );
單個(gè)空格包圍操作符(除了像加的一元操作符和邏輯非),例:
- a = b; // don't use a=b;
- for (int i = 0; i < 10; ++i) // don't use for (int i=0; i<10; ++i)
- // or
- // for(int i=0;i<10;++i)
7.3 表格格式化
行的一個(gè)邏輯塊應(yīng)該作為一個(gè)表格被格式化:
- string name = "Mr. Ed";
- int myValue = 5;
- Test aTest = Test.TestYou;
對(duì)于表格的格式化用空格而不用制表符因?yàn)樵谀承┲票矸s進(jìn)設(shè)置會(huì)使表格格式化看起來(lái)是很奇怪。
8. 命名習(xí)慣
8.1 大寫(xiě)格式
8.1.1 Pascal Casing
習(xí)慣大寫(xiě)每個(gè)單詞的第一個(gè)字母(就像在TestCounter)。
8.1.2 Camel Casing
習(xí)慣除了第一個(gè)單詞外大寫(xiě)每個(gè)單詞的第一個(gè)字母例如testCounter。
8.1.3 全大寫(xiě)情況
對(duì)于只有一兩個(gè)字符縮寫(xiě)組成的標(biāo)識(shí)符才用全大寫(xiě)的情況。有三個(gè)或更多個(gè)字符組成的標(biāo)識(shí)符應(yīng)該用Pascal情況代替。例如:
- public class Math
- {
- public const PI = ...
- public const E = ...
- public const feigenBaumNumber = ...
- }
8.2. 命名指導(dǎo)方針
通常根據(jù)指導(dǎo)方針在名字和命名內(nèi)用低線字符對(duì)Hungarian 符號(hào)來(lái)說(shuō)被認(rèn)為是壞習(xí)慣。
Hungarian 符號(hào)是一組應(yīng)用于命名來(lái)映射變量類型的前綴和后綴。這種命名風(fēng)格在早期的Windows程序中被廣泛應(yīng)用,但現(xiàn)在被取消了至少不提倡了。如果你遵循這個(gè)指南用Hungarian 符號(hào)是不允許的。
但要記住一個(gè)好的變量名描述了語(yǔ)義而不失類型。
對(duì)于這個(gè)規(guī)則有個(gè)例外就是GUI編碼。包括像按鈕(buttton)的GUI元素,所有領(lǐng)域和變量名都應(yīng)該帶有它們類型名的后綴不是縮寫(xiě)。例如:
- System.Windows.Forms.Button cancelButton;
- System.Windows.Forms.TextBox nameTextBox;
8.2.1 類命名指導(dǎo)方針
· 類命名必須是名詞或名詞短語(yǔ)。
· UsePascal 情況參考8.1.1
· 不要用任何類前綴
8.2.2 接口命名指導(dǎo)方針Guidelines
· 用可以描述行為的名詞或名詞短語(yǔ)或形容詞命名接口。(例如IComponent 或 IEnumberable)
· 用Pascal情況(參考8.1.1)
· 用I作為名字的前綴,它應(yīng)該緊跟一個(gè)大寫(xiě)字母(接口名的第一個(gè)字母)
8.2.3 枚舉命名指導(dǎo)方針
· 用Pascal情況命名枚舉值名字和類型名字
· 枚舉類型和枚舉值不要前綴
· 對(duì)于枚舉用單一名字
· 對(duì)于位領(lǐng)域用復(fù)數(shù)名字
8.2.4 只讀和常量命名
· 用名詞,名詞短語(yǔ)或名詞的縮寫(xiě)命名靜態(tài)領(lǐng)域
· 使用Pascal 情況(參考8.1.1)
8.2.5 參數(shù)/非常量領(lǐng)域命名
· 一定要用描述性名字,應(yīng)該能夠足夠表現(xiàn)變量的意義和它的類型。但一個(gè)好的名字應(yīng)該基于參數(shù)的意義。
· 使用Camel情況(參考8.1.2)
8.2.6 變量命名
· 計(jì)數(shù)變量當(dāng)用在瑣碎的計(jì)數(shù)循環(huán)式更適宜叫i, j, k, l, m, n。(參考10.2例如對(duì)全局計(jì)數(shù)的更智能命名等等)—
· 使用Camel情況(參考8.1.2)
8.2.7 方法命名
· 用動(dòng)詞或動(dòng)詞短語(yǔ)命名方法。
· 使用Pascal(參考8.1.2)
8.2.8 屬性命名
· 用名詞或名詞短語(yǔ)命名屬性
· 使用Pascal 情況(參考8.1.2)
· 考慮用與其類型相同的名字命名一個(gè)屬性
8.2.9 事件命名
· 用事件處理器后綴命名事件處理器
· 用sender 和 e命名兩個(gè)參數(shù)
· 使用Pascal情況(參考8.1.1)
· 用EventArgs 后綴命名事件參數(shù)
· 用現(xiàn)在和過(guò)去時(shí)態(tài)命名有前綴和復(fù)制概念的事件名字。
· 考慮用一個(gè)動(dòng)詞命名事件。
8.2.10 大寫(xiě)總結(jié)
Type | Case | Notes |
Class / Struct | Pascal Casing | |
Interface | Pascal Casing | Starts with I |
Enum values | Pascal Casing | |
Enum type | Pascal Casing | |
Events | Pascal Casing | |
Exception class | Pascal Casing | End with Exception |
public Fields | Pascal Casing | |
Methods | Pascal Casing | |
Namespace | Pascal Casing | |
Property | Pascal Casing | |
Protected/private Fields | Camel Casing | |
Parameters | Camel Casing |
9. 編程習(xí)慣
9.1 可見(jiàn)性
不要任何公共實(shí)例或類變量,讓它們?yōu)樗接械摹?duì)于私有成員最好不用“private”作修飾語(yǔ)什么都不寫(xiě)。私有是默認(rèn)情況,每個(gè)C#程序員都應(yīng)該知道這一點(diǎn)。
用屬性代替。你可以用公共靜態(tài)(或常量)對(duì)于這個(gè)規(guī)則是以例外,帶它不應(yīng)該是規(guī)則。
9.2 沒(méi)有“幻”數(shù)
不要用幻數(shù),也就是在源代碼中直接用常數(shù)值。替代這些后者以防變化(比方說(shuō),你的應(yīng)用程序可以處理3540用戶代替427你的代碼在50行中通過(guò)分散25000LOC)是錯(cuò)誤和沒(méi)有收益的。聲明一個(gè)帶有數(shù)的常量來(lái)代替:
- public class MyMath
- {
- public const double PI = 3.14159...
- }
10. 編碼舉例
10.1 Brace placement example
- namespace ShowMeTheBracket
- {
- public enum Test {
- TestMe,
- TestYou
- }
- public class TestMeClass
- {
- Test test;
- public Test Test {
- get {
- return test;
- }
- set {
- test = value;
- }
- }
- void DoSomething()
- {
- if (test == Test.TestMe) {
- //...stuff gets done
- } else {
- //...other stuff gets done
- }
- }
- }
- }
括弧應(yīng)該在以下情況之后以新行開(kāi)始:
· 命名空間聲明(注意這在0.3版本中是新添的與0.2版本不同)
· 類/接口/結(jié)構(gòu)聲明
· 方法聲明
10.2 變量命名舉例
代替:
- for (int i = 1; i < num; ++i) {
- meetsCriteria[i] = true;
- }
- for (int i = 2; i < num / 2; ++i) {
- int j = i + i;
- while (j <= num) {
- meetsCriteria[j] = false;
- j += i;
- }
- }
- for (int i = 0; i < num; ++i) {
- if (meetsCriteria[i]) {
- Console.WriteLine(i + " meets criteria");
- }
- }
- try intelligent naming :
- for (int primeCandidate = 1; primeCandidate < num; ++primeCandidate)
- {
- isPrime[primeCandidate] = true;
- }
- for (int factor = 2; factor < num / 2; ++factor) {
- int factorableNumber = factor + factor;
- while (factorableNumber <= num) {
- isPrime[factorableNumber] = false;
- factorableNumber += factor;
- }
- }
- for (int primeCandidate = 0; primeCandidate < num; ++primeCandidate)
- {
- if (isPrime[primeCandidate]) {
- Console.WriteLine(primeCandidate + " is prime.");
- }
- }
注意:索引變量通常叫i, j, k 等等。但Note: Indexer variables generally should be called i, j, k etc. But 萬(wàn)一像這樣,使得重新考慮這個(gè)原則更有意義。一般來(lái)說(shuō),當(dāng)同一個(gè)計(jì)數(shù)器或索引器被重用,給它們有意義的名字。
聯(lián)系客服