C# 3.0新語言特性和改進(下篇)
[2] Lambda表達式和Lambda表達式樹
上一篇我們介紹了C# 3.0新語言特性和改進上部分,這篇我們繼續介紹剩下的部分。
C# 3.0新語言特性和改進包括:
- 自動屬性(Auto-Implemented Properties)
- 隱含類型局部變量(Local Variable Type Inference)
- 匿名類型(Anonymous Types)
- 對象與集合初始化器(Object and Collection Initializers)
- 擴展方法(Extension Methods)
- Lambda表達式和Lambda表達式樹 (Lambda Expression and Lambda Expression Trees)
擴展方法(Extension Methods)
往往我們需要對CLR類型進行一些操作,但苦于無法擴展CLR類型的方法,只能創建一些helper方法,或者繼承類。我們來修改上面的User類:
public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Read() { return "Id:" + Id + "姓名:" + Name + "年齡:" + Age; } }
然后調用
var user = new { Id = 1, Name = "YJingLee", Age = 22 }; var str = user.Read();
現在有了擴展方法就方便多了。
擴展方法允許開發人員往一個現有的CLR類型的公開契約(contract)中添加新的方法,而不用生成子類或者重新編譯原來的類型。擴展方法有助于把今天動態語言中流行的對duck typing的支持之靈活性,與強類型語言之性能和編譯時驗證融合起來。——引用Scott博文
擴展方法是可以通過使用實例方法語法調用的靜態方法。效果上,使得附加的方法擴展已存在類型和構造類型成為可能。他可以對現有類功能進行擴充,從而使該類型的實例具有更多的方法(功能)。
擴展方法允許我們在不改變源代碼的情況下擴展(即添加不能修改)現有類型中的實例方法。
擴展方法給我們一個怎樣的思路呢?我們一步一步做一下!
首先聲明擴展方法:通過指定關鍵字this修飾方法的第一個參數。注意擴展方法僅可聲明在靜態類中。擴展方法具備所有常規靜態方法的所有能力,可以使用實例方法語法來調用。接著就可以調用擴展方法了。下面通過一個具體的實例分析一下:
例如我們要檢查一個字符串變量是否是合法的電子郵件地址?在.Net2.0框架下像這樣:
var email = "leeyongjing@gmail.com"; if (EmailValidator.IsValid(email)) { Response.Write("YJingLee提示:這是一個正確的郵件地址"); }
而使用擴展方法的話,我可以添加“IsValidEmailAddress()”方法到string類本身中去,該方法返回當前字符串實例是否是個合法的字符串。
if (email.IsValidEmailAddress()) { Response.Write("YJingLee提示:這是一個正確的郵件地址"); }
我們是怎么把這個IsValidEmailAddress()方法添加到現有的string類里去的呢?先定義一個靜態類,再定義“IsValidEmailAddress”這個靜態的法來實現的。
public static class Extensions//靜態類 { public static bool IsValidEmailAddress(this string s) //靜態方法和this { Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"); return regex.IsMatch(s); } }
注意,上面的靜態方法在第一個類型是string的參數變量前有個“this”關鍵詞,這告訴編譯器,這個特定的擴展方法應該添加到類型為“string”的對象中去。然后在IsValidEmailAddress()方法實現里,我可以訪問調用該方法的實際string實例的所有公開屬性/方法/事件,取決于它是否是合法電子郵件地址來返回true/false。
擴展方法不僅能夠應用到個別類型上,也能應用到.NET框架中任何基類或接口上。即可用于整個.NET框架豐富的可組合的框架層擴展。
擴展方法要點
- 擴展方法的本質為將實例方法調用在編譯期改變為靜態類中的靜態方法調用。事實上,它確實擁有靜態方法所具有的所有功能。
- 擴展方法的作用域是整個namespace可見的,并且可以通過using namespace來導入其它命名空間中的擴展方法。
- 擴展方法的優先級:現有實例方法優先級最高,其次為最近的namespace下的靜態類的靜態方法,最后為較遠的namespace下的靜態類的靜態方法。
- 擴展方法是一種編譯時技術,注意與反射等運行時技術進行區別,并慎重使用。