LINQ體驗(3)——C# 3.0新語言特性和改進(下篇)

來源:互聯網
上載者:User

上一篇我們介紹了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架構豐富的可組合的架構層擴充。

擴充方法要點
  1. 擴充方法的本質為將執行個體方法調用在編譯期改變為靜態類中的靜態方法調用。事實上,它確實擁有靜態方法所具有的所有功能。
  2. 擴充方法的範圍是整個namespace可見的,並且可以通過using namespace來匯入其它命名空間中的擴充方法。
  3. 擴充方法的優先順序:現有執行個體方法優先順序最高,其次為最近的namespace下的靜態類的靜態方法,最後為較遠的namespace下的靜態類的靜態方法。
  4. 擴充方法是一種編譯時間技術,注意與反射等運行時技術進行區別,並謹慎使用。

 

Lambda運算式和Lambda運算式樹狀架構 (Lambda Expression andLambda Expression Trees)Lambda運算式

我們從“所有字串尋找包含YJingLee子字串”說起。在C# 2.0中,匿名方法允許我們以內聯的方式來實現委託執行個體,它提供強大的函數式程式設計語言,但是標記顯得相當的冗長和帶有強制性。我們使用C# 2.0 中的匿名方法尋找,代碼如下:

var inString = list.FindAll(delegate(string s) { return s.Indexof("YJingLee") >= 0; });

現在可以使用C# 3.0帶來的Lambda運算式允許我們使用一種更接近人的思維、更自然的方式來實作類別似於匿名方法同樣的效果,看下面的代碼多麼簡潔:

var inString = list.FindAll(s => s.Indexof("YJingLee") >= 0);

Lambda運算式格式:(參數列表)=>運算式或語句塊
具體意義:定義Lambda接受參數列表,運行運算式或語句塊返回運算式或語句塊的值傳給這個參數列表。

Lambda運算式參數類型可以是隱式類型或顯式類型。在顯式列表中,每個參數的類型是顯式指定的,在隱式列表中,參數的類型由Lambda運算式出現的語境自動推斷類型。
Lambda運算式的參數列表可以有一個或多個參數,或者無參數。在有單一的隱型參數的lambda運算式中,圓括弧可以從參數列表中省略。
例如:

(x, y) => x * y;//多參數,隱式類型=>運算式x => x * 10;//單參數,隱式類型=>運算式x => { return x * 10; }; //單參數,隱式類型=>語句塊(int x) => x * 10;//單參數,顯式類型=>運算式(int x) => { return x * 10; };//單參數,顯式類型=>語句塊() => Console.WriteLine(); //無參數

下面看這個例子:
在前面的文章中,我們寫了一個User類及增加了2個人,接下來,我們使用由LINQ提供的新的Where和Average方法來返回集合中的人的一個子集,以及計算這個集合中的人的平均年齡:

List<User> user = new List<User>{        new User{Id=1,Name="YJingLee",Age=22},        new User{Id=2,Name="XieQing",Age=25},};var results = user.Where(p => p.Name == "YJingLee").ToList();// 擷取特定人時所用的過濾條件,p參數屬於User類型var average = user.Average(p => p.Age);// 用User對象的Age值計算平均年齡

如下:

對這個Lambda運算式做個簡要分析:

var resultsdelegate = user.Where(delegate(User p){      return p.Name == "YJingLee";// 返回一個布爾值});var averagedelegate = user.Average(delegate(User p){       return p.Age;});

Lambda運算式L可以被轉換為委託類型D,需要滿足以下條件:
L的參數類型要與D的參數個數相等,類型相同,傳回型別相同,無論是運算式,還是語句塊。注意隱式類型要參與類型辨析。

Lambda運算式樹狀架構

Lambda運算式樹狀架構允許我們像處理資料(比如讀取,修改)一樣來處理Lambda運算式。我以一個例子簡單說明:

Expression<Func<int, bool>> filter = n => (n * 3) < 5;BinaryExpression lt = (BinaryExpression)filter.Body;BinaryExpression mult = (BinaryExpression)lt.Left;ParameterExpression en = (ParameterExpression)mult.Left;ConstantExpression three = (ConstantExpression)mult.Right;ConstantExpression five = (ConstantExpression)lt.Right;var ne = filter.Compile();Console.WriteLine("Result: {0},{1}", One(5),One(1));Console.WriteLine("({0} ({1} {2} {3}) {4})", lt.NodeType,mult.NodeType, en.Name, three.Value, five.Value);

如下:


Lambda運算式和Lambda運算式樹狀架構要點

  1. Lambda運算式的參數類型可以忽略,因為可以根據使用的上下文進行推斷。
  2. Lambda運算式的主體(body)可以是運算式,也可以是語句塊。
  3. Lambda運算式傳入的實參將參與類型推斷,以及方法重載辨析。
  4. Lambda運算式和運算式體可以被轉換為運算式樹狀架構。
  5. 運算式樹狀架構允許lambda運算式能夠代表資料結構替代表示為執行代碼。

好了,我在這裡簡單的把C# 3.0新語言特性和改進說了一下,接下來,正式進入這個系列的主題部分——LINQ。為了讓大家瞭解,我換一種手法來寫,從一條一條LINQ語句分析來貫穿LINQ的知識點。一起體驗LINQ帶給我們的樂趣。敬請關注from:李永京

相關文章

聯繫我們

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