自己總結的C#編碼規范--1.命名約定篇:http://www.cnblogs.com/luzhihua55/p/CodingConventions1.html
自己總結的C#編碼規范--2.命名選擇篇:http://www.cnblogs.com/luzhihua55/p/3868258.html
自己總結的C#編碼規范--3.特定場景下的命名最佳實踐:http://www.cnblogs.com/luzhihua55/p/3873015.html
命名約定
我們在命名標識符時(包括參數,常量,變量),應使用單詞的首字母大小寫來區分一個標識符中的多個單詞,如UserName.
-
PascalCasing
PascalCasing包含一到多個單詞,每一個單詞第一個字母大寫,其余字母均小寫。例如:HelloWorld、SetName等。
除了參數、變量、常量外,所有命名空間名稱、類、函數、接口、屬性、事件、枚舉等名稱的命名,使用 Pascal 風格。
-
camelCasing
camelCasing包含一到多個單詞,第一個單詞首字母小寫,其余單詞首字母大寫。例如:name、productId等。
參數與變量的命名使用camelCasing.
-
SCREAMING_CAPS
SCREAMING_CAPS包含一到多個單詞,每個單詞的所有字母都大寫,單詞與單詞之間用"_"連接,該風格目前在c#中只用于const常量。
如:public const string DEFAULT_PAGE = "default.aspx";
-
私有變量的命名
Private 的私有變量使用下劃線"_"+camelCasing的大小寫規則,以便快速確認該變量的作用域。
如: private int _userId;
-
首字母縮寫詞的大小寫
首字母縮寫詞是由一個短語的首字母組成的,如Xml(ExtensibleMarkuLaguage),IO(Input and Output)。它和單詞縮寫是有區別的,單詞縮寫僅僅是把一個單詞的長度變短。
-
把兩個字母的首字母縮寫詞全部大寫,除非它是camelCasing的第一個單詞。
using System.IO;
public void StartIO(Stream ioStream)
-
由三個或以上的字母組成的首字母縮寫詞,只有第一個字母大寫,如Xml,Html.除非首字母是camelCasing標識符的第一個單詞。
using System.Xml;
public void ProcessXmlNode(XmlNode xmlNode)
-
復合詞的大小寫
不要把復合詞中的首字母大寫。復合詞要當成一個單詞來處理。
如endpoint, callback,metadata,namespace等都是正確的寫法
-
在帶單位的值的變量后加上"_camelCasing單位"
將單位加入標識符命名中,可以使使用者快速準確的知道傳人數據的單位,減少錯誤的發生。
如public void CreateCache(int cacheSize)
傳入的數據是bytes, KB, MB 還是GB?
改成public void CreateCache(int cacheSize_mb)
一目了然,并且會減少調用者傳入錯誤數據的可能。
其他一些沒有單位的函數參數以及帶單位的版本。
-
不要使用匈牙利命名法
匈牙利命名法是指用小寫形式的數據類型縮寫來作為變量名的前綴。如:strName,intCount。
這種命名法在C和C++時代很流行,可以幫助程序員記住自己的類型。
但在C#中需要禁用,除非你有足夠的理由,因為:
-
C#都是強類型的,現在的IDE(如Visual Studio)可以自動的檢測出當前變量的類型以及類型錯誤
- 開發初期經常需要修改變量的類型,使用匈牙利命名法維護很困難。
-
使用英語語序命名標識符
人在閱讀代碼時,能更快的理解符合其閱讀習慣的命名。
如VerticalAlignment比AlignmentVertical能讓人更快的知道該變量的含意。
簡單的講,看到一個標識符一定要可以見名知意。
-
名字一定要能夠表達出標識符的含意
標識符名字必須要表達出該標識符的意義,絕對不可以使用無意義的v1,v2…vn之類的命名。
public static void CloneChars(char[] cl1, char[] cl2)
{
for (var i = 0; i < cl1.Count(); i++)
{
cl2[i] = cl1[i];
}
}
代碼的調用者不看這函數是無法知道cl1還是cl2是要拷貝的char數組,他必須進到這個函數去看完整個邏輯才可以調用。而且在看的過程中cl2[i] = cl1[i]; 也需要他花幾秒鐘來思考是做什么的。
如果改成有意義的名字: source 和target那么這個方法調用者一看名字就知道使用方法了。
public static void CloneChars(char[] source, char[] target)
{
for (var i = 0; i < source.Count(); i++)
{
target[i] = source[i];
}
}
-
選擇意義單一明確的名字
在命名時要使用專業的單詞,避免使用"空洞"的單詞
如: class BinaryTree
{
public int Size()
看到這行代碼你想到Size會返回什么,樹的高度,節點數還是樹在內存中的空間?
我們可以使用更單一明確的詞來告訴讀者這個方法的具體含義,如Height,NodesNum,Memory_Bytes
-
使用不會產生歧義的名字
在給標識符命名時,一定不能產生歧義,代碼中的很多錯誤都是由于命名時的歧義造成的。例如:
public const int CART_TOO_BIG_LIMIT = 10;
if (ShoppingCart.Count() >= CART_TOO_BIG_LIMIT)
{
LogError("Too many items in cart.");
}
這段代碼有個很經典的"大小差一缺陷"。在判斷購物車物品上限時,我是應該使用 ">"還是應該使用">=",我是無法從代碼中判斷出來的,所以這個地方很容易出現bug.如果我們換成MAX_ITEMS_IN_CART, 那我馬上就可以判定出這里要使用">"。
-
命名要與使用者的期望相匹配
有些名字之所以會讓人誤解是因為帶嗎閱讀者對它們有先入為主的印象,就算你本意并非如此。這種情況下,你最好是選用一個與使用者期望所匹配的名字。
如很多程序員都習慣了把Get開始的方法當作"輕量級訪問器",他只是簡單的返回成員變量。
大家看到以下的代碼
class BinaryTree
{
public int GetNodesCount()
會以為只是返回內部private int _nodesCount; 私有變量的訪問器。
但如果實際你的代碼可能是一個非常耗時的代碼,內部實現是廣度優先遍歷所有的樹節點,還要去數據庫查找父節點和子節點的關系,然后累加。
那么這么一個耗時的方法可能由于你的命名,導致了被調用者反復多次的調用,導致整個系統性能下降。
如果你將命名改為ComputeNodesCount那么調用者就會知道這是個耗時的操作,需要緩存調用結果并減少調用。
-
為名字附加更多的信息
一個變量名就像一個小注釋,盡管空間不大,但不管你在命中擠進任何額外的信息,每次有人看到命名時都會看到這些信息。
例子:當你從網頁接收了請求的表單,里面可能還有不安全的代碼,如注入語句等,這時你在命名時需要體現該數據不安全,可以使用unsafeFormData,當調用完安全檢查方法后可以將其改為 safeFormData = HandleUnsafeData(unsafeFormData).這樣代碼閱讀者就知道可以放心的使用該變量了。
下表給出了更多需要給名字附加額外信息的例子
-
不要賣弄風騷
使用最常用,眾所周知的單詞。不要在代碼命名時賣弄你的學識,要讓你的代碼快速準確的表達出你的想法才是真正的牛人。
如public static string ConvertXml2Html (string sourcePath)
有些人在看到這個方法的時候怎么想也想不明白這個2是做什么用的,是把一個Xml文件變成兩個Html?
熟悉英語文化的人可能知道這是To的俚語表達。如果你不能保證所有閱讀你代碼的人都知道2是To的縮寫。那么請使用ConvertXmlToHtml命名。
特定場景下的命名最佳實踐
-
命名空間
-
要使用PascalCasing,并用點號來分隔名字空間中的各個部分。
如Microsof.Office.PowerPoint
- 要用公司名作為命名空間的前綴,這樣就可以避免與另外一家公司使用相同的名字。
- 要用穩定的,與版本無關的產品名稱作為命名空間的第二層
- 不要使用公司的組織架構來決定命名空間的層次結構,因為內部組織結構經常改變。
-
不要用相同的名字來命名命名空間和該空間內的類型。
例如,不要先將命名空間命名為Debug,然后又在該空間中提供Debug類。大部分編譯器包括VS要求用戶在這樣的類型前加上完整的限定符。
-
要讓接口的名字以字母I開頭
如IComponet,IDisposable 大家一看就知道是接口。
同時要確保如果一個類是一個接口的標準實現,那么這個類和接口應該只差一個"I"前綴。
-
派生類的末尾使用基類名稱
例如,從 Stream 繼承的 Framework 類型以 Stream 結尾,從 Exception 繼承的類型以 Exception 結尾。
-
泛型類型參數的命名
-
使用描述性的名字來命名泛型類型參數,并且在前面加上T前綴
如下面都是很好的命名
public delegate TOutput Converter<TInput, TOutput>(TInput from);
-
如果只有一個類型參數,可以只用一個字母T來表示泛型
public class Nullable<T>
public class List<T>
-
如果泛型參數有約束,那么需要在泛型類型參數名中需要顯示出該約束
public interface ISessionChannel<TSession> where TSession:ISession
-
枚舉類型的命名
-
要用單數名詞而不是復數命名枚舉類型,如要用ConsoleColor而不是ConsoleColors
public enum ConsoleColor
{
Red,
Yellow,
Blue
}
-
不要給枚舉類型加"Enum"、"Flag"等后綴。
ColorEnum,ColorFlag都不好,因為本身就是枚舉,再加上就是沒有意義的重復 。
-
要用動詞和動詞短語命名方法
-
屬性的命名
- 要用名詞、名詞短語或形容詞來命名屬性
-
要用描述集合中具體內容的短語的復數形式來命名屬性集合,而不要用短語的單數形式加"List"、"Array"或"Collection"后綴
class BinaryTree
{
//Good Naming
public NodeCollection Nodes { get; set; }
//Bad Naming
public NodeCollection NodesCollection { get; set; }
-
要用肯定性的短語命名布爾屬性。最好在前面選擇性的加入"Is"、"Can"、"Has"等前綴。
CanSeek比CantSeek和Seekable都更準確和容易理解。
-
事件的命名
-
要用動詞或動詞短語命名事件
如: Clicked、Painting、DroppedDown 等等
-
要用現在進行時(ing)和過去式(ed)來賦予事件發生之前和之后的概念。而不是使用Before和After.
如窗口關閉前發生的close事件應該命名為Closing,而在窗口關閉之后發生的應該命名為Closed.
-
字段的命名
- 禁止使用實例的公有字段和受保護字段,請使用屬性代替。
Tips:在VisualStudio中輸入"prop"可快速創建外部可修改的屬性,輸入"propg"可快速創建不允許外部修改的屬性。如:
//propg
public int NodesCount { get; private set; }
//prop
public List<BinaryNode> Nodes { get; set; }
- 一般只使用靜態字段
- 要使用名詞、名詞短語或形容詞命名字段
- 不要給字段加前綴如"g_"、"s_"來表示靜態字段。因為字段和屬性是非常相似的,所以要遵循相同的命名規范。
文章列表