天天看點

c# 3.0 初體驗 1

      大家可能都回抱怨為什麼c#發展的回這麼快呢?可能有很多的人連2.0都沒有深入的接觸,是的,我們已經有了3.0了。不用抱怨,因為c#比起來其他的一些語言來說太“年輕”了,是以它當然有很多需要改進的地方,需要提高的地方。在二三年前,大家都覺得其實c#就是microsoft從java抄襲過來一個面向對象的語言,可以從近幾年的發展來看,java的速度已經明顯跟不上c#的腳步了。比如java5.0中的泛型,看起來更像是sun給java的framework打的一塊更新檔而已,嚴格來說java的泛型是假的,因為當你編譯一個Java泛型類時,編譯器會将所有的類型參數替換為Object。當然,如果你嘗試建立一個List<int>,你就需要對所有的int進行裝箱。是以,這會有很大的開銷。另外,為了讓VM高興,編譯器必須為所有的類型插入類型轉換。如果一個List是Object的,而你想将這些Object視為Customer,就必須将Object轉換為Customer,以讓類型檢查器 滿意。而它在實作這些的時候,真的隻是為你插入所有這些類型轉換。是以,你隻是嘗到了文法上的甜頭,卻沒有獲得任何執行效率。當然我不是有意貶低java語言,而是從某一個側面來看問題,大家不要是以來罵我。說到底,我覺得變化是好事情,也就是微軟正在為它的c#語言不斷的完善,作為程式員,我們不能簡單一勞永逸,而是要随時最好充電的準備,你準備好了嗎?好了,言歸正傳,我們開始我們的c#3.0初體驗,在第一次我們主要看一下,這次微軟又為我們帶來了什麼新的東西,并且對将來的開發人員來說會有哪些友善呢?順便說一句,我進入第一家公司一直都是在.net framework 1.1上開發,2.0上的新特性都是自己學的,現在才有了用武之地。

C#3.0主要的語言上新特性有以下:

       ●匿名類型(還記得2.0中的匿名方法嗎?哈哈,真搞)

       ●隐含類型局部變量

       ●擴充方法

       ●表達式樹

       ●對象與集合初始化器

       ●查詢表達式(LINQ)--絕對是牛鼻的東西

       ●Lambda表達式

        這些隻是一些從開發人員角度來說的東西,如果從平台方面來看,微軟對它的虛拟機在性能上的提升也是值得我們關注的。接下來我們一個一個來解釋一下。

隐含類型局部變量

        有過vb經驗的朋友對這條一定很熟悉,看以下表達式:

       var i=5;

       var s="qigaoopan";

       var ym=new[] {2423,234,7456};

       var為關鍵字,他不是一個類型,我們可以看作一個占位符号,編譯器會在編譯的時候進行類型的推斷,來确定我們到底申明了什麼類型。初始化的右邊必須是一個表達式,并且編譯時可以推斷類型。比如我們var b=null,編譯的時候就會出現編譯錯誤。如果有人變态真寫出一個自定義類型var,那麼編譯器會以系統var為最高優先級别來處理,說到這裡,希望大家注意c#的編碼規範。類型的命名不能和系統的關鍵字沖突。并且var的申明僅僅限制與局部變量的申明,我們也可以用在foreach循環和using語句中。在foreach我們的編譯器會自動推斷集合中的元素的實際的類型,我們這樣寫的代碼在通用性上有很大的提高,這些技巧也可以提高代碼的複用性。也就是代碼的抽象層次提高了。但是我們不能狂用這些trick,會對代碼的性能有很大的損傷。看最後一個例子,數組也可以作為隐含類型,以前版本的c#中我們肯定不能這樣幹,但是現在我們可以了,編譯器可以自動推斷這個數組的類型,int[]數組。如果我們的數組中的類型不統一,那麼在編譯的時候我們就會遇到編譯錯誤,即隐含類型推斷的時候出現了問題,我們說所有的類型都是從object來的,可以把所有的類型都轉化到object,但是編譯器是不會做這樣自動的轉換的。也就是編譯器不會把隐含類型的數組轉換成object數組。

       總結一下這個特征就是,它是一個編譯時的小功能。

擴充方法

      顧名思義,擴充方法允許我們在不改動源代碼的情況下擴充現有類型中的執行個體方法。(感覺類似動态語言的特征)看下邊的例子:

     public static class Qigaopan{

              public static void Study(this string s){

                           ......................

   }

  }

  String s="Microsoft ,Go";

        s.Do();

       大家可能注意到了Study方法中的this參數,其實我們在s上調用Do方法的時候會傳遞s進入方法,相當于Qigaopan.Do(s)。

  注意我們是在不改變源代碼的情況下去添加的,也就是在二進制不受破壞的前提下作的這種擴充。注意我們一定要使用靜态類,隻有靜态類中才有靜态方法。擴充一個類的方法我們一般有:通過繼承,包含的方式,即組合的方式,第三種就是反射技術。我們可以通過在運作時通過反射來添加一些新的特性到類上。在3.0種微軟為我們帶來第四種方法。就是我們上邊看到的擴充發放,我們隻能通過這種發式擴充,而不能收縮。

  總結以下就是擴充方法的本質是将執行個體方法調用在編譯期間改變為靜态類的靜态方法的調用,擴充方法是一種編譯時技術,我們不能過度的使用,注意和反射技術的差別。擴充方法并不是對設計的颠覆,隻是給我們提供了一些更加靈活的來加強我們的設計,而不是鼓勵我們不用認真地去設計。我們在設計的時候不能依賴于擴充方法,其實擴充方法就是一種對設計的彌補。比如我們的adapter設計模式,我們在現有代碼的基礎上去做轉換的時候才會用到,如果讓我們重新去設計,我們肯定不會去在用adapter模式了。很顯然我們在上便的QIgaopan類型中擴充了string類型的方法,我們不能再一個類型中擴充好幾個類型,比如在添加和一個方法叫做public static void YM(this int i){}這樣的東西,這就違背了語言的初衷。

對象和集合初始化器

  我們在編寫類型的時候會寫一些構造器,有了對象初始化器,我們可以有以下代碼:

  public class Point{  

    int x,y;

    public int X{get......}

    public int Y{get.......}

   }

   var a=new Point{X=0,Y=1}

   相當于:var a=new Point();a.X=0;a.Y=1;

   集合初始化器:List<int> num=new List<int>{0,1,2,3,4,5};這也是一中編譯時的轉換技術,可以使我們以更加友善的方式來初始化集合。

   總結下:對象初始化器實際上利用了編譯器對對象中對外可見的字段和屬性進行按序指派;集合初始化器會對初始化器中的元素進行按序調用add方法。

匿名類型

  看例子:var qi=new {Name=“qigaopan”,Age=“25”,Marrige=“no”};

var qi1=new {Name=“qigaopan”,Age=“24”,Marrige=“no”}

qi=qi1;

  編譯器可以通過第一句推斷出我們的類型中有什麼東西,首先是兩個屬性,然後是兩個字段,還有一個無參數的構造器。類似于我們申明了這樣一個類型:

class TypeName{ 

   public string Name{get,set}

   public string Age{get,set}

   public string Marrige{get,set}

   public string name,age,marrige;

  }

  其實匿名類型使用new來建立了一個匿名的對象,這就給我們提供了一中更加友善的方式。以前我使用一個簡單的類型的時候要寫一大堆的屬性,現在我們直接使用,編譯器會知道我們的意圖,而建構一個合适的類型來給我們使用。匿名類型直接繼承自System.Object。其實就如同我們上公共汽車一樣,我們拿出來錢根本不需要告訴售票員我們要買票,售票員就會知到我們的意圖。如之前的例子我們指定了連個屬性相同的匿名類型,那麼他們會使同一個類型,比如qi和qi1是同一個類型。

  我們隻是說了文法的表面現象,我們不能隻看表面,而要看語言機制,然後我們提升某個語言機制的認識,我們要站在更高的一個層次來看一種語言的某個機制如何使用,内在機制,由這種機制提煉出來的某種管用法,一種模式,也就是我們如何更好的使用這種機制。任何一種機制都是一把雙刃劍,有好的方面,也有不好的一個方面。是以感覺在編寫代碼向上的方向上,我們一定要注意對機制的把握。

一看時間都快12:30了,呵呵,睡覺了,有時間繼續和大家分享3.0。寫的不對的地方希望大家隻出來。

繼續閱讀