還不錯的參考書:编写高质量代码:改善C#程序的157个建议
1.避免將多個類別放在一個文件裡面。
2. 一個文件應該只有一個命名空間,避免將多個命名空間放在同一個文件裡面。
3. 一個文件最好不要超過500行的程式碼(不包括IDE產生的程式碼)。
4. 一個方法的程式碼長度最好不要超過25行。
5. 避免方法中有超過5個參數的情況。使用結構來傳遞多個參數。
6. 每行程式碼不要超過80個字元。
7. 不要手工的修改IDE產生的程式碼。
● 如果需要編輯IDE產生的程式碼,編輯格式和風格要符合該編碼標準。
● Use partial classes whenever possible to factor out the maintained portions.
8. 避免利用注釋解釋顯而易見的程式碼。
● 程式碼應該可以自解釋。好的程式碼由可讀的變數和方法命名因此不需要注釋。
9. Document only operational assumptions, algorithm insights and so on.
10. 避免使用方法級的文檔。
● 使用延伸的API文檔說明之。
● 只有在該方法需要被其他的開發者使用的時候才使用方法級的注視。(在C#中就是///)
11. 不要硬編碼數字的值,總是使用構造函數設定其值。
12. 只有是自然結構才能直接使用const,比如一個星期的天數。
13. 避免在只讀的變數上使用const。如果想實現只讀,可以直接使用readonly。
public class MyClass
{
public readonly int Number;
public MyClass(int someValue)
{
Number = someValue;
}
public const int DaysInWeek = 7;
}
14. 每個假設必須使用Assert檢查
● 平均每15行要有一次檢查(Assert)
using System.Diagnostics;
object GetObject()
{
//...
}
object obj = GetObject();
Debug.Assert(obj != null);
15. 程式碼的每一行都應該通過白盒方式的測試。
16. 只拋出已經顯示處理的異常。
17. 在捕獲(catch)語句的拋出異常子句中(throw),總是拋出原始異常維護原始錯誤的堆棧分配。
catch(Exception exception)
{
MessageBox.Show(exception.Message);
throw ; //和throw exception一樣。
}
18. 避免方法的返回值是錯誤程式碼。
19. 盡量避免定義自定義異常類別。
20. 當需要定義自定義的異常時:
● 自定義異常要繼承于ApplicationException。
● 提供自定義的序列化功能。
21. 避免在單個程式集里使用多個Main方法。
22. 只對外公布必要的操作,其他的則為internal。
23. Avoid friend assemblies, as it increases inter-assembly coupling.
24. Avoid code that relies on an assembly running from a particular location.
25. 使應用程式集盡量為最小化程式碼(EXE客戶程式)。使用類別庫來替換包含的商務邏輯。
26. 避免給列舉變數提供顯式的值。
//正確方法(○)
public enum Color { Red,Green,Blue }
//避免(×)
public enum Color { Red = 1,Green = 2,Blue = 3 }
27. 避免指定特殊類型的列舉變數。
//避免
public enum Color : long { Red,Green,Blue }
28. 即使if語句只有一句,也要將if語句的內容用大括號括起來。
29. 避免使用trinary條件。
30. 避免在條件語句中調用返回bool值的函數。可以使用局部變數並檢查這些局部變數。
bool IsEverythingOK()
{
//...
}
//避免
if (IsEverythingOK ())
{
//...
}
//替換方案
bool ok = IsEverythingOK();
if (ok)
{
//...
}
31. 總是使用基於0開始的數組。
32. 在循環中總是顯式的初始化引用類型的數組。
public class MyClass { }
MyClass[] array = new MyClass[100];
for(int index = 0; index < array.Length; index++)
{
array[index] = new MyClass();
}
33. 不要提供public 和 protected的成員變數,使用屬性代替他們。
34. 避免在繼承中使用new而使用override替換。
35. 在不是sealed的類別中總是將public 和 protected的方法標記成virtual的。
36. 除非使用interop(COM+ 或其他的dll)程式碼否則不要使用不安全的程式碼(unsafe code)。
37. 避免顯示的轉換,使用as進行兼容類型的轉換。
Dog dog = new GermanShepherd();
GermanShepherd shepherd = dog as GermanShepherd;
if (shepherd != null )
{
//...
}
38. 當類別成員包括委託的時候
● Copy a delegate to a local variable before publishing to avoid concurrency race condition.
● 在調用委託之前一定要檢查它是否為null
public class MySource
{
public event EventHandler MyEvent;
public void FireEvent() {
EventHandler temp = MyEvent;
if(temp != null ) {
temp(this,EventArgs.Empty);
}
}
}
39. 不要提供公共的事件成員變數,使用事件訪問器替換這些變數。
public class MySource {
MyDelegate m_SomeEvent ;
public event MyDelegate SomeEvent
{
add { m_SomeEvent += value; }
remove { m_SomeEvent -= value; }
}
}
40. 使用一個事件幫助類別來公布事件的定義。
41. 總是使用接口。
42. 類別和接口中的方法和屬性至少為2:1的比例。
43. 避免一個接口中只有一個成員。
44. 盡量使每個接口中包含3-5個成員。
45. 接口中的成員不應該超過20個。
● 實際情況可能限制為12個
46. 避免接口成員中包含事件。
47. 避免使用抽象方法而使用接口替換。
48. 在類別層次中顯示接口。
49. 推荐使用顯式的接口實現。
50. 從不假設一個類型兼容一個接口。Defensively query for that interface.
SomeType obj1;
IMyInterface obj2;
/* 假設已有程式碼初始化過obj1,接下來 */
obj2 = obj1 as IMyInterface;
if (obj2 != null)
{
obj2.Method1();
}
else
{
//處理錯誤
}
51. 表現給最終用戶的字串不要使用硬編碼而要使用資源文件替換之。
52. 不要硬編碼可能更改的基於配置的字串,比如連接字串。
53. 當需要构建長的字串的時候,使用StringBuilder不要使用string
54. 避免在結構裡面提供方法。
● 建議使用參數化構造函數
● 可以重載
55. 總是要給靜態變數提供靜態構造函數。
56. 能使用早期綁定就不要使用後期綁定。
57. 使用應用程式的日志和跟蹤。
58. 除非在不完全的switch語句中否則不要使用goto語句。
59. 在switch語句中總是要有default子句來顯示訊息(Assert)。
int number = SomeMethod();
switch(number)
{
case 1 :
Trace.WriteLine("Case 1:");
break;
case 2 :
Trace.WriteLine("Case 2:");
break;
default :
Debug.Assert(false);
break;
}
60. 除非在構造函數中調用其他構造函數否則不要使用this指針。
// 正確使用this的例子
public class MyClass
{
public MyClass(string message ){}
public MyClass() : this("hello") {}
}
61. 除非你想重寫子類別中存在名稱衝突的成員或者調用基底類別的構造函數否則不要使用base來訪問基底類別的成員。
// 正確使用base的例子
public class Dog
{
public Dog(string name){ }
virtual public void Bark( int howLong) { }
}
public class GermanShepherd : Dog
{
public GermanShe pherd(string name): base (name) { }
override public void Bark(int howLong) { base.Bark(howLong); }
}
62. 基於樣版的時候要實現Dispose()和Finalize()兩個方法。
63. 通常情況下避免有從System.Object轉換來和由System.Object轉換去的程式碼,而使用強制轉換或者as替換。
