C#編碼簡單性之泛型篇(如何編寫簡短的C#代碼,隨時更新)

來源:互聯網
上載者:User

作者:陳勇

出處:blog.csdn.net/cheny_com

這是編碼簡單性系列中的其中一篇,之前幾篇包括代碼篇/函數篇/語義篇。 因為要積累案例,會隨時更新。

 

之前提到:編碼簡單性的“心法”就是:只要螢幕上有任何兩部分代碼看上去相似,則一定有合并辦法。而說起相似,沒有比switch - case的各段代碼更相似的了。如果細數一下自己產品中最長的函數,裡邊幾乎肯定的有一個switch - case,或者一堆if -else if(兩者其實等同)。一般各段代碼看似相同,又有點不同,既不能變成函數,也不能變成類,怎麼辦呢?

解決臭長的switch-case的最好方法,就是泛型(在C++時代叫做模板)。泛型不好學,但是卻很重要。02年左右的時候曾經作為流程改善人員進行代碼審查,無意中發現一段在pagedown的時候做波浪狀起伏的代碼,觀察發現其中有65個函數其實可以縮減為1個函數(沒錯,65:1),其內容是在5種int常數下,處理13種不同的變數,而處理方法完全相同。這段代碼共有4000行,已經耗時一個月,編程者月薪7000(那是10年前,7000元可以購買5平米小產權房,或2平米大產權房);當天下午它們就變成了1個函數,長度不足55行。據此推斷,每年因為不能靈活使用泛型而造成的經濟損失,可能達到億元以上。

案例1 2011-05-27 一個簡單泛型類

下面一段代碼很簡短,顯得很不值得改造,但其實除了Display之外還有很多函數,其中一些case體很長,而且各種type日後層出不窮,因此不得不進行改造。

Display的目的,是讓各種各樣的udc們以自己的方式顯示器Value中的數值:

        public static MvcHtmlString Display(this HtmlHelper htmlHelper, UDC udc)        {            switch (udc.Type)            {                case "Text100":                    return new MvcHtmlString((udc.Value != null) ? udc.Value.ToString() : "NULL");                case "Text20":                    return new MvcHtmlString((udc.Value != null) ? udc.Value.ToString() : "NULL");                case "Date":                    return new MvcHtmlString(((DateTime)udc.Value).ToShortDateString());                default: return new MvcHtmlString(string.Format("Unknown UDC type: {0}", udc.Type));            }        }

為了能夠拆開這個函數,需要聲明

    public interface IUDC    {        ……        MvcHtmlString Display { get; }        ……    }

然後讓一個類(這個類一般都存在了)繼承這個介面,並實現其方法:

    public partial class UDCText100 : IUDC     {        ……        public MvcHtmlString Display { get { return new MvcHtmlString((Value != null) ? Value.ToString() : "NULL"); } }        ……    }

而顯示方式也從@Html.Display(udc)變成@udc.Display。

這段代碼整個修改後,原來的5個switch-case只剩下1個,代碼明顯更內聚了,也就是每次增加一個類型,基本只需要在一個地方(partial class)內完成修改,就可以了;修改的成果在編譯時間就能確認是否充分和正確(而在其中switch-case中漏掉一個類型,只有在啟動並執行時候case找不到才知道)。

 案例2 2011-05-29 泛型函數

        private IUDC GetOrDefaultUDC<T, V>(Table<T> table, ..., V defaultValue) where T : class, IUDC, new()        {            var t = table.SingleOrDefault(...);            if (t == null)            {                t = new T();                ...                t.OValue = defaultValue;                 ...            }            return t;        }

這個泛型函數從一類表中取出一條記錄,如果沒有,則建立它。由於建立的時候需要new 一個新的紀錄,而且新紀錄依據table的不同,某些欄位的預設值也不同。用傳統的方法需要編寫很多函數,而且每當出現一種新的這類表,又需要編寫新的函數。本文開頭提到的的那個65個函數就是因此而產生的。

處理這類情況的心法是:如果發現由於類型的差異一些看起來很像的代碼無法合并為函數,那麼就應該用泛型了

這種情況下用泛型需要掌握兩種主要技術:new()和Ixxx(某Interface)。new的目的是讓T可以建立(如果函數中不建立就不需要了),而Interface的目的是保證編譯時間刻就能確保未來的新類型依然可以使用這個函數(C++的時代只有用到新的類型的時候才可以確認)。

 

這裡只談泛型的應用思想,關於泛型的應用技術,在MSDN有一篇很好的文章可供參考:http://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx。此文將整個C#泛型的發展曆程從頭到尾講了一遍。

 

點擊下載免費的敏捷開發教材:《火星人敏捷開發手冊》

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.