C#/Net代碼精簡最佳化技巧(3)

來源:互聯網
上載者:User
文章目錄
  • 1 隱式類型
  • 2 Linq 擴充方法
  • 3 擴充方法
  • 4 System.IO.Path
  • 5 泛型委派
  • 總結

前面兩篇中已經介紹了10個小技巧,本篇是本次系列的最後一篇,將再介紹5個。這些小技巧看著並不起眼,有些您可能知道,但在平時的開發中可能由於慣性並沒有去使用。所以建議大家掌握並去使用這些小技巧,他們將使我們的代碼變得更簡潔和易於維護。

1 隱式類型

首先瞭解一下概念,隱式類型並不是動態類型,隱式類型是用關鍵字var來定義,var定義的類型仍然是強型別。

很多人認為使用隱式類型是懶惰的表現,剛開始我也是這麼認為的,但是想想我使用STL中迭代指標的開發經理,我就明白了。看下面代碼:

for (list<int>::const_iterator it = myList.begin(); it != myList.end(); ++it){    // ...}

很多時候我們會寫出下面這樣的代碼

// pretty obviousActiveOrdersDataAccessObject obj = new ActiveOrdersDataAccessObject(); // still obvious but even more typingDictionary<string,List<Product>> productsByCategory =     new Dictionary<string,List<Product>>();

上面的代碼的類型定義很明顯,是什麼類型就用什麼類型來定義,下面嘗試用var關鍵字來定義

// nicer!var obj = new ActiveOrdersDataAccessObject();// Ah, so much nicer!var productsByCategory = new Dictionary<string,List<Product>>();

用var關鍵字後代碼變得簡潔多了,編譯器會在編譯時間去推斷是什麼類型,var關鍵字只相當於是一個預留位置。

而且使用var關鍵字在我們使用泛型或是Linq運算式時會提供更好的可讀性,比較下面兩行代碼:

// 隱式類型var results1 = from p in products where p.Value > 100 group p by p.Category;// 顯示類型IEnumerable<IGrouping<string, Product>> results2 =     from p in products where p.Value > 100 group p by p.Category;
2 Linq 擴充方法

在以前的編碼中,很多時候我們需要去寫一些自己的函數庫,如排序、分組、尋找或是其他的一些演算法。並且我們要花很多的時間來為這些函數寫單元測試,很多時候困擾我們的一些bug正是在這些方法中出現的。

隨著Linq擴充方法的推出,你可以使用現成的這些標準的演算法,而不需要自己再去寫一遍,提供了極大的方便。需要排序可以使用OrderBy(),當需要查詢條件時可以使用Where(),當需要選擇一些類的屬性時可以使用Select(),當需要分組查詢時可以使用GroupBy(),這些Linq中的擴充方法經過了全面的測試,不需要我們來為他寫單元測試代碼,也不會出現讓人困擾的bug。

看下面的例子,假設有一個集合List<Product>,集合裡裝載的是Product對象,Product有Value和Category兩個屬性,現在要按類別來尋找Value值大於$100的資料,以前我們可能會像下面這樣寫

var results = new Dictionary<string, List<Product>>();foreach (var p in products){    if (p.Value > 100)    {        List<Product> productsByGroup;        if (!results.TryGetValue(p.Category, out productsByGroup))        {            productsByGroup = new List<Product>();            results.Add(p.Category, productsByGroup);        }        productsByGroup.Add(p);    }}

使用Linq擴充方法

var results = products               .Where(p => p.Value > 100)               .GroupBy(p => p.Category);

也可以像下面這樣寫

var results = from p in products where p.Value > 100 group p by p.Category;
3 擴充方法

擴充方法可以讓我們自己對一些類型進行方法的擴充,像上面講到的Linq的一些擴充方法。擴充方法是一個靜態方法,而且必須在一個靜態類中。看下面這個例子,編寫一個擴充方法將所以對象轉換成XML。

public static class ObjectExtensions{    public static string ToXml(this object input, bool shouldPrettyPrint)    {        if (input == null) throw new ArgumentNullException("input");        var xs = new XmlSerializer(input.GetType());        using (var memoryStream = new MemoryStream())        using (var xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding()))        {            xs.Serialize(xmlTextWriter, input);            return Encoding.UTF8.GetString(memoryStream.ToArray());        }    }}

需要注意的是,包含擴充方法的類必須為靜態類;擴充方法必須為靜態方法;方法的第一個參數必須在類型前面使用this關鍵字。下面看看怎樣調用該擴充方法

// can convert primatives to xmlstring intXml = 5.ToXml();// can convert complex types to xmlstring objXml = employee.ToXml();// can even call as static method if you choose:objXml = ObjectExtensions.ToXml(employee);

其實擴充方法只是一個文法糖,他可以使我們在類型上添加一些自己的方法。適當的使用擴充方法可以給我們的編碼帶來方便,但過度使用會適得其反,會使代碼易讀性變差,而且我們的只能提示項也會變得非常龐大。

4 System.IO.Path

Net中的System.IO.Path方法有很多的靜態方法來處理檔案和路徑。很多時候我們嘗試手動的將路徑和檔案名稱結合在一起而導致產生的檔案路徑不可用,因為我們往往忽視了路徑後面可能有一個結尾符號‘\’。現在使用Path.Combine()方法可以避免這種錯誤

string fullPath = Path.Combine(workingDirectory, fileName);

假設現在有一個帶檔案名稱的完整的路徑名,我們需要取其中的路徑、檔案名稱或是檔案的副檔名。Path類的很多靜態方法可以滿足我們的需要,如下

string fullPath = "c:\\Downloads\\output\\t0.html";// gets "c:\"string pathPart = Path.GetPathRoot(fullPath);// gets "t0.html"string filePart = Path.GetFileName(fullPath);// gets ".html"string extPart = Path.GetExtension(fullPath);// gets "c:\downloads\output"string dirPart = Path.GetDirectoryName(fullPath);

所以當我們遇到這種需要對檔案路徑進行操作時,我們可以去使用Path類的靜態方法。

5 泛型委派

如果你寫過或使用過帶事件的類,或是用過Linq的一些擴充方法,那麼您很多可能直接或間接的使用過委託。委託可以以一種強有力的方式類建立一個類型,用來描述一個方法的簽名。在運行時來使用和調用這個方法。這個有點類似於C++中的函數指標。

委託最偉大的是比類的繼承有更好的重用性,假設你要設計一個緩衝類,該類有一些方法供使用者調用,但是取決於快取項目是否到期或是被刪除了。你向使用者提供一個抽象方法,讓使用者去繼承類並重載該方法,這意味著增加了很多額外的工作。

如果使用委託,可以在被調用是在指定的方法中進行快取項目的到期檢查,可以傳遞或設定委託方法,匿名委託或是lambda運算式進行調用,這樣沒有必須建立子類,我們可以將類設定成密封的以防止任何意外的發生,這樣使類更加安全和有更好的可重用性。

那麼這些和泛型委派有什麼關係呢?現在有三個委託的基本“類型”反覆的出現,而又不想去反覆寫這些委託類型。就要使用泛型委派了,泛型委派還可以提高我們代碼的可讀性。下面是三個Net提供的泛型委派類型

Action<T>

Predicate<T>

Func<TResult>

關於上面三個泛型委派類型的詳細解釋和用法,可以點選連結看MSDN

再回到剛才說到的緩衝的例子,你希望該緩衝接受一個緩衝策略,並且有一個委託,委託的傳回值來表示緩衝是否到期,代碼如下:

public sealed class CacheItem<T>{    public DateTime Created { get; set; }    public DateTime LastAccess { get; set; }    public T Value { get; set; }}public sealed class Cache<T>{    private ConcurrentDictionary<string, CacheItem<T>> _cache;    private Predicate<CacheItem<T>> _expirationStrategy;    public Cache(Predicate<CacheItem<T>> expirationStrategy)    {        // set the delegate        _expirationStrategy = expirationStrategy;    }    // ...    private void CheckForExpired()    {        foreach (var item in _cache)        {            // call the delegate            if (_expirationStrategy(item.Value))            {                // remove the item...            }        }    }}

 

現在就可以建立和使用緩衝類了

var cache = 
new Cache<int>(item => DateTime.Now - item.LastAccess > TimeSpan.FromSeconds(30));

事實上我們可以發揮我們的想象對緩衝建立很多的到期策略,但不要去使用繼承。瞭解和使用泛型委派他會增加我們類的可重用性。

總結

本文是參考老外系列部落格的第三篇寫的,並不是直譯,原文見下面連結。希望本文對大家有所協助。

原文連結:http://geekswithblogs.net/BlackRabbitCoder/archive/2010/09/09/c.net-five-final-little-wonders-that-make-code-better-3.aspx

 

C#/Net代碼精簡最佳化技巧(1)

C#/Net代碼精簡最佳化技巧(2)

C#/Net代碼精簡最佳化技巧(3)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.