亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C#零基礎入門08:代碼規范

2019-11-14 16:05:09
字體:
來源:轉載
供稿:網友

一:前言

沒有規矩,不成方圓。在代碼的世界中,尤其這樣。作為程序員,我們不想讓我們的代碼寫出去之后被人恥笑:看,連個換行都換的這么不專業。作為開發主管,我們則不想我們的組員寫出來的代碼各類風格都有,五顏六色的,極其丑陋。寫出規范的代碼,首先需要訓練,其次,也有一定的手段或者工具來進行輔助。本小節,我們就要從這兩方面入手,講講如何規范我們的代碼。當然,由于我們現在學到的編碼知識還有限,最為規范來講,本小節也將僅僅會設計那些最基本,最常用的編碼的規范,但是即便如此,學完本小節之后,也會讓我們的代碼看上去專業多了。

注意:我不喜歡一次性將全部的知識點講完,比如,規范,我們今天可能只會涉及到80%的部分。我喜歡這個“二八原則”,即,我們只花20%的時間來完成80%的事情,但是,如果我們想完成剩下的20%的事情,反過來就要額外付出80%的時間,這就有點性價比不那么高了。對于培訓或者說學習知識來說,這個“二八原則”很重要。我們的培訓,如果要講解100%的知識點,首先會很枯燥(因為有些知識需要我們具備鉆牛角尖的精神才能悟透),其次會很費時間(難道我們不想花最少的時間學習最多的知識嗎?),最后,成為真正的專家,從來不是被培訓出來的,所以我們的培訓,會教會你這80%的部分,剩下的,則希望這80%中已經培養給你的習慣,自己去挖掘。OK,今天廢話有點多,言歸正傳,雖然隨著我們的課程我們還沒寫了多少行的代碼,但是即便如此,我相信你也一定覺得現在到了該規范代碼的時候了。我們到目前為止,也進行了幾次的重構,重構的過程,實際就是講代碼一步步引導到更規范的過程。當然,有些規范,可能是學習完本小節課程我們就會掌握的,而更深入的規范,就需要我們在今后的學習中慢慢掌握了,而且有意思的一點是:規范本身可能還存在沖突性。。。好了,不管怎么樣,個中滋味,以后我們慢慢體會吧,現在,GO……

 

二:命名規范

1: 考慮在命名空間中使用復數

如果有一組功能相近的類型被分組到了同一個命名空間下,則可以考慮為命名空間使用復數。

最典型的例子有,在FCL中,我們需要把所有的非泛型集合類集中在一起存放,所以我們就有了System.Collections命名空間。這樣的命名規范,好處就是即便我們從來沒有使用過集合類,但是看到這樣的命名空間,我們也會知道在它之下是和集合(即Collection)相關的一些類型。不要出現System.AllCollections、System.TheCollection這樣的命名,這看上去要么太繁瑣、要么含義不清。

舉一個實際的例子,如果我們的項目中存在一系列PRocessor類型,則可以使用命名空間Processors。

2: 用名詞和名詞組給類型命名

類型是什么?面向對象方面的先驅者會告訴我們,類型對應著現實世界中的實際對象。對象在語言學中意味它是一個名詞。所以,類型也應該以名詞或名詞組去命名。

類型定義了屬性和行為。它包含行為,但不是行為本身。所以,下面的一些命名對于類型來說是好的命名:

OrderProcessor;

ScoreManager ;

CourseRepository;

UserControl;

DomainService;

相應的,如下的類型名稱則被認為是不好的典范:

OrderProcess

ScoreManage

CourseSave

ControlInit

DomainProvide

動詞類的命名更像是類型內的一個行為,而不是類型本身。

3: 用形容詞組給接口命名

接口規范的是“Can do”,也就是說它規范的是類型可以具有哪些行為。所以,接口的命名應該是一個形容詞組,如:

IDisposable,表示類型可以被釋放;

IEnumerable,表示類型含有Items,可以被迭代。

正是因為接口表示的是類型的行為,所以從語義上我們可以讓類型繼承多個接口,如:

class SampleClass : IDisposable, IEnumerable<SampleClass>
{
    //省略
    #region 實現IDisposable

    public void Dispose()
    {
        throw new NotImplementedException();
    }

    #endregion

    #region 實現IEnumerable
    public IEnumerator<SampleClass> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
    #endregion
}

以上的代碼我們寫起來會覺得既符合語法,又符合語義。如果,我們將接口命名為IDisposal,這給人造成的誤解是該類型是一個類,而不是接口,雖然我們在前面加了前綴I,但仍然感覺這是符合語義的。

不過話又說來,FCL中也有一些違反此規定的例外,比如IEnumerator接口。但是,這種情況相對來說還是比較少的,在大多數情況下,我們需要始終考慮用形容詞來為接口命名。

4: 以復數命名枚舉類型,以單數命名枚舉元素

枚舉類型應該具有復數形式,它表達的是將一組相關元素組合起來的語義。比如:

enum Week
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

在這里,Week對于星期幾來說,具備復數含義。如果我們這里將Week修改為Day,那么在調用的代碼會變成如下:

Day.Monday

它不會比下面的代碼來的簡潔明了:

Week.Moday

5: 用PascalCasing命名公開元素

開放給調用者的屬性、字段和方法,都應該采用PascalCasing命名方式,比如:

class Person
{
    public string FirstName;
    public string LastName;

    public string Name
    {
        get
        {
            return string.Format("{0} {1}", FirstName, LastName);
        }
    }

    public string GetName()
    {
        return Name;
    }
}

這樣,調用者在調用方的代碼看起來如下:

person.Name

如果我們不注意這樣的命名規則,讓調用方的代碼看起來是這樣的:

person.name

我們首先會懷疑name是個什么類型,其次也會懷疑其可訪問性。

6: 用camelCasing命名私有字段和局部變量

私有字段和局部變量只對本類型負責,它們在命名方式也采用和開放的屬性及字段不同的方法。camelCasing很適合這類命名。

camelCasing和PascalCasing的區別是它的首字母是小寫的。之所以要采用兩種不同的命名規則,是為了便于開發者自己快速地區分它們。

在建議123中我們為公開元素給出了一個命名示例,下面的示例,則是私有字段和局部變量的一個示例:

class Person
{
    private string firstName;
    private string lastName;

    public string Name
    {
        get
        {
            return string.Format("{0} {1}", firstName, lastName);
        }
    }

    private int doSomething(int a, int b)
    {
        int iTemp = 10;
        return a + b + iTemp;
    }
}

在這里例子中,我們可以看到,所有的私有字段,包括方法的參數及局部變量全部遵循首字母小寫的camelCasing規則。一旦我們脫離了這種規則,那么在編碼過程中很容易就給自己造成混淆。firstName是什么,難道它不是個私有字段,而是個公開屬性嗎?這太混亂了,也太可怕了,因為作為開發者的我們不得不回到變量的命名處才知道它的訪問范圍。

7: 考慮使用肯定性的短語命名布爾屬性

布爾值無非就是True和False,所以,應該用肯定性的短語來表示它,如:以Is、Can、Has作為前綴。

布爾屬性正確命名的一個示例如下:

class SampleClass
{
    public bool IsEnabled { get; set; }

    public bool IsTabStop { get; set; }

    public bool AllowDrop { get; set; }

    public bool IsActive { get; }

    public bool? IsChecked { get; set; }
}

以上的這些命名都來自于.NET最新的WPF子集,其中AllowDrop雖然不是以肯定性短語作為前綴,但是其作為動作表達了一個是與否的含義,所以也是一個推薦的布爾型屬性的推薦命名。

布爾型屬性命名的反面教材如下:

class SampleClass
{
    public bool Checked { get; set; }
    public bool Loaded { get; set; }
}

肯定性形容詞或者短語雖然表達了一個肯定的含義,但是這些單詞或者短語現在都被用于命名事件或委托變量,所以不應該用于布爾屬性。

 

三:代碼整潔

1: 總是提供有意義的命名

除非惡意為之,否則永遠不要為自己的代碼提供無意義的命名。

害怕需要過長的命名才能提供足夠的意義?不要怕,其實我們更介意的是在讀代碼的時候出現一個iTemp。

int i這樣的命名方式只應該出現在循環中(如for循環),除此之外,我們找不到任何理由在代碼的其他地方出現這樣的無意義命名。

2: 方法抽象級別應在同一層次

方法的抽象級別應在同一個層次上,我們來看下面的代碼:

class SampleClass
{
    public void Init()
    {
        //本地初始化代碼1
        //本地初始化代碼2
        RemoteInit();

    }

    void RemoteInit()
    {
        //遠程初始化代碼1
        //遠程初始化代碼2
    }
}

Init方法本意要完成初始化動作,而初始化包括本地初始化和遠程初始化。在這段代碼中,Init方法內部代碼的組織結構是本地初始化代碼直接運行在方法內部,而遠程初始化代碼卻被封裝為一個方法在這里被調用。這顯然是不妥當的,因為本地初始化和遠程初始化的地方是相當的。作為方法來講,如果遠程初始化代碼作為方法存在,則本地初始化代碼也應該作為方法存在。

所以,上面的代碼應該重構為:

class SampleClass
{
    public void Init()
    {
        LocalInit();
        RemoteInit();
    }

    void LocalInit()
    {
        //本地初始化代碼1
        //本地初始化代碼2
    }

    void RemoteInit()
    {
        //遠程初始化代碼1
        //遠程初始化代碼2
    }
}

重構后的代碼看上去清晰明了,所有的方法的抽象級別都在一個層次上,作為閱讀者的我們一眼看上去就知道Init方法完成了什么樣的功能。

3: 一個方法只做一件事

“單一職責原則(SRP)”要求每個類型只負責一件事情。我們將此概念擴展到方法上,就變成了:一個方法只做一件事。

什么樣的代碼才叫“做同一件事”?參照上一個建議中的代碼,其中,LocalInit方法和RemoteInit方法是兩件事情,但是在同一抽象層次上,在類型這個層次對外又可以將其歸并為“初始化”這一件事情上。所以,“同一件事”要看抽象所處的地位。

下面的方法就完成了太多事情,我們來看這段實際的代碼:

private uint status;

private uint DeveloperID;

private uint flags;

public string CheckDogAndGetKey()
{
    flags = SentinelKey.SP_STANDALONE_MODE;
    status = oSentinelKey.SFNTGetLicense(DeveloperID, oSentinelKeysLicense.SOFTWARE_KEY, SentinelKeysLicense.LICENSEID, flags);

    if (status != SentinelKey.SP_SUCCESS)
    {
        throw new FileNotFoundException("未檢查到合法的加密狗,或者未正確安裝驅動");
    }

    status = oSentinelKey.SFNTReadString(SentinelKeysLicense.SP_1ST_STRING, readStringValue, MAX_STRING_LENGTH);

    if (status != SentinelKey.SP_SUCCESS)
    {
        throw new FileNotFoundException("讀取加密狗數據失敗");
    }

    return System.Text.Encoding.ASCII.GetString(readStringValue).Substring(0, 7);
}

在方法CheckDogAndGetKey中,方法既要負責檢測加密狗是否被正確安裝,又要負責從加密狗中讀取相關的信息。顯然,這讓CheckDogAndGetKey來說,責任太多。我們可以考慮將方法重構為如下兩個方法:

void CheckDog()
{
    flags = SentinelKey.SP_STANDALONE_MODE;
    status = oSentinelKey.SFNTGetLicense(DeveloperID, oSentinelKeysLicense.SOFTWARE_KEY, SentinelKeysLicense.LICENSEID, flags);

    if (status != SentinelKey.SP_SUCCESS)
    {
        throw new FileNotFoundException("未檢查到合法的加密狗,或者未正確安裝驅動");
    }

}

string GetKeyFormDog()
{
    status = oSentinelKey.SFNTReadString(SentinelKeysLicense.SP_1ST_STRING, readStringValue, MAX_STRING_LENGTH);
    if (status != SentinelKey.SP_SUCCESS)
    {
        throw new FileNotFoundException("讀取加密狗數據失敗");
    }

    return System.Text.Encoding.ASCII.GetString(readStringValue).Substring(0, 7);
}

經過重構,每個方法都只要負責一件事情。并且,從命名來看,CheckDog負責檢測加密狗,而GetKeyFormDog則負責獲取信息。

4: 避免過長的方法和過長的類

若不遵循“一個方法只做一件事”及類型的“單一職責原則”,則往往會產生過長的方法和過長的類。

如果方法過長,則意味著可以站在更高的層次上重構出若干個更小的方法。那么,有沒有具體的指標提示方法是否過長?有,是以行數做指標的,有人建議一個方法不要超過10行,有人建議不要超過30行。當然,這沒有唯一標準,在我看來,如果一個方法在Visual Studio中需要滾屏才能閱讀完,那么就肯定有些過長了,必須想法重構它。

對于類型,除非有非常特殊的理由,類型的代碼不要超過300行。如果行數太多了,則要考慮能否重構。

5: 只對外公布必要的操作

那些不是很必要公開的方法和屬性,private之。如果需要公開的方法和屬性超過9個,在Visual Studio默認的設置下,就需要滾屏才能顯示在Intellisense中了,查看圖:

wps_clip_image-15377

在上圖中我們可以看到,Intellisense在可見范圍內為我們提示的方法還包括了從Object繼承過來的3個方法,實際真正在這個例子中能為我們顯示的有價值的信息只有6條。Sample類型的全部代碼如下:

class SampleClass
{
    int field1;
    int field2;
    int field3;

    public int MyProperty1 { get; set; }

    public int MyProperty2 { get; set; }

    public int MyProperty3 { get; set; }

    public int MyProperty4 { get; set; }

    public int MyProperty5 { get; set; }

    public int MyProperty6 { get; set; }

    public void Mehtod1()
    {
    }

    public void Mehtod2()
    {
    }

    public void Mehtod3()
    {
    }
}

如果我們為SampleClass增加更多的公開屬性或方法,則意味著我們在使用Intellisense的時候增加了查找成本。

若我們打算將某個方法public或internal,請仔細考慮這種必要性。記住,Visual Studio默認給我們生成的類型成員的訪問修飾符就是private的,在我看來,這是微軟在給我們心理暗示:除非必須,否則關閉訪問。

除了類成員外,類型也一樣,應將不該對其他項目公開的類型設置為internal。想想類型默認的訪問限制符是internal,這意味著類型如果我們沒有有意為之,類型就應該只對本項目開放。所以,遵守這個規則,這會使我們的API看上去清爽很多。

 

四:代碼規范靜態檢查工具

除了我們自己要習慣性掌握的規范外,這個世界上當然還有一些靜態檢查工具來幫我們分析我們的代碼是否符合一定的規范。目前來說,我們習慣性的做法就是使用StyleCop來幫我們完成代碼規范的靜態檢查。

StyleCop是什么?

StyleCop早年是微軟自己內部的靜態代碼和強制格式美化工具。雖然流出來的微軟的一些開源項目,跑跑StyleCop,我們仍舊會發現出現很多警告(當然,我們也可以理解為MS各個項目本身定義了自己都有的一些規范)。其官方地址為:

http://archive.msdn.microsoft.com/sourceanalysis

在本小節的此時此刻,當前版本為:StyleCop-4.7.44.0,下面我們來看看如何使用StyleCop進行代碼的規范檢查。

備注:視頻中使用到的規范設置文件下載地址為:http://back.zuikc.com/Settings.zip

 

五:視頻

非公開部分,請聯系最課程(www.zuikc.com)


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品国产自产在线老师啪| 国产精品久久久久久五月尺| 日韩av一区二区在线| 亚洲免费人成在线视频观看| 亚洲最大福利视频网站| 国产亚洲精品91在线| 永久555www成人免费| www.xxxx欧美| 国内精品久久久久伊人av| 亚洲精品成人av| 欧美日韩国产色| 国产精品无av码在线观看| 日韩精品免费在线视频| 日本一区二三区好的精华液| 欧美国产一区二区三区| 欧美一级淫片videoshd| 亚洲电影天堂av| 国产成人精品免高潮费视频| 亚洲国产免费av| 成人欧美一区二区三区黑人孕妇| 国产精品女视频| 欧美在线视频播放| 精品亚洲永久免费精品| 欧美影院成年免费版| 91久久精品国产| 亚洲一级一级97网| 亚洲伊人久久大香线蕉av| 九九热这里只有精品免费看| 日韩视频在线免费| 亚洲性生活视频在线观看| 九九热这里只有在线精品视| 成人黄色av免费在线观看| 久久精品男人天堂| 久久国产精品久久久久久久久久| 欧美高清理论片| 97久久伊人激情网| 欧美在线一区二区视频| 国产亚洲激情在线| 国产97在线视频| 日本精品va在线观看| 欧美日韩国产精品一区二区三区四区| 日韩精品在线观看一区| 91美女片黄在线观| 日韩在线视频一区| 国产亚洲精品久久久久动| 亚洲国产天堂久久综合网| 亚洲成人国产精品| 91精品久久久久久久久中文字幕| 在线a欧美视频| 国产精品白嫩美女在线观看| 国产精品啪视频| 97人洗澡人人免费公开视频碰碰碰| 九九九热精品免费视频观看网站| 欧日韩不卡在线视频| 色偷偷91综合久久噜噜| 丝袜情趣国产精品| 91久久在线观看| 国产乱肥老妇国产一区二| 日韩女优人人人人射在线视频| 国产精品私拍pans大尺度在线| 国产欧美va欧美va香蕉在| 国产精品27p| 国产精品视频久久久久| 亚洲成人网在线| 97人人模人人爽人人喊中文字| 亚洲视频欧美视频| 久久久久国色av免费观看性色| 国产精品美女999| 欧美日韩国产精品一区二区不卡中文| 亚洲男人7777| 欧美日韩国产一区二区| 国产99视频精品免视看7| 中文字幕在线日韩| 亚洲最大av网| 欧美日韩国产成人在线| 另类少妇人与禽zozz0性伦| 国模吧一区二区三区| 国产在线a不卡| 全亚洲最色的网站在线观看| 久久免费视频在线观看| 国产一区二区黄| 亚洲加勒比久久88色综合| 久久免费国产精品1| 国产成人一区二| 丝袜亚洲欧美日韩综合| 国产男女猛烈无遮挡91| 国产成人精品最新| 97精品国产91久久久久久| 国产欧美日韩丝袜精品一区| 亚洲aⅴ男人的天堂在线观看| 久久精品国产成人| 日韩二区三区在线| 97香蕉久久超级碰碰高清版| 亚洲精品视频网上网址在线观看| 茄子视频成人在线| 中文一区二区视频| 91精品视频网站| 日韩美女视频中文字幕| 91国产美女视频| 日韩免费在线观看视频| 九九热精品在线| 亚洲日韩中文字幕| 性色av一区二区三区在线观看| 亚洲第一区中文字幕| 精品自在线视频| xvideos成人免费中文版| 日韩久久精品电影| 欧美日韩性视频在线| 欧美日韩国产精品一区| 亚洲精品久久久久久久久久久| 久久久91精品国产一区不卡| 久久国产一区二区三区| 亚洲高清色综合| 狠狠躁夜夜躁久久躁别揉| 国产欧美精品在线播放| 国产亚洲一区二区在线| 国产精品麻豆va在线播放| 久久久久久久久国产精品| 成人在线视频网| 国产精品美女免费视频| 亚洲视频777| 98视频在线噜噜噜国产| 国产做受69高潮| 亚洲国产精品女人久久久| 久久天天躁狠狠躁老女人| 亚洲欧美另类中文字幕| 久久久久久免费精品| 久久久久久美女| 韩国三级电影久久久久久| 亚洲精品国产综合久久| 精品国模在线视频| 亚洲伊人成综合成人网| 精品日本高清在线播放| 中文字幕国产精品久久| 91av福利视频| 国产精品自产拍高潮在线观看| 欧美日韩中文字幕| 国产精品第1页| 日本一区二区三区在线播放| 亚洲xxx自由成熟| 国产精品日韩欧美大师| 精品久久久久国产| 国产中文欧美精品| 亚洲精品日韩久久久| 日韩中文在线观看| 欧美一区在线直播| 欧美激情综合亚洲一二区| 亚洲人成伊人成综合网久久久| 成人xxxxx| 亚洲国产黄色片| 精品伊人久久97| 午夜精品99久久免费| 日韩中文综合网| 中文字幕日韩免费视频| 国产激情久久久久| 国产亚洲精品久久久久动| 久久全球大尺度高清视频| 色爱精品视频一区| 国产精品99一区| 欧美成人精品h版在线观看| 日本中文字幕不卡免费| 亚洲精品理论电影| 91九色国产社区在线观看| 亚洲成人久久一区|