C# 3.0 新特性 學習(二):匿名類型、擴展方法


這兩天看了一下msdnwebcast上的visual studio 2008的系列課程,記錄下所學的知識,以便加深記憶 

1.匿名類型

顧名思義 匿名類型就是沒有名字的類型。在C#3.0中允許我們在程序中聲明一個臨時的類型來存儲數據,例如:

1      class Program
2     {
3          static  void Main( string[] args)
4         {
5              // 聲明一個匿名對象,擁有 Name和Age 屬性
6               var obj =  new { Name =  " Joey ", Age =  25 };//這里的new { Name =  " Joey ", Age =  25 } 就是一個匿名類型 ,obj則是這個類型的一個對象,稱為匿名對象
7             Console.WriteLine( " 匿名對象obj : Name= " + obj.Name +  "  , Age= " + obj.Age);
8         }
9     }

 

上述代碼中,我們聲明了一匿名對象obj ,然后輸出對象的屬性值。如果在VS 你將鼠標移到 obj前面的var 上面,vs 會提示:obj 是一個匿名類型 ‘a 。這個‘a 是編譯器自動作為標識的一個類型,匿名對象在編譯時,編譯器還是得給它一個類型。其實上面的匿名類型 new { Name = "Joey", Age = 25 } 是直接從Object繼承過來的, 相當於

public  class  'a{
public string Name{get;private set;}

        public int Age{get;private set;}  

這樣的一個擁有只讀屬性的自定義類型。

在MSDN 中匿名類型的定義是這樣的:

   1.匿名類型提供了一種方便的方法,可用來將一組只讀屬性封裝到單個對象中,而無需首先顯式定義一個類型。

   2.類型名由編譯器生成,並且不能在源代碼級使用。每個屬性的類型由編譯器推斷。

   3.可通過使用 new 運算符和對象初始值創建匿名類型。

上面三句話是所謂的”說到點子上了”.讓人一看就明白匿名類型。但是在這里,我還得提一提,匿名類型和var 隱式類型化的聲明關鍵字的關系;很多新手在看到var 聲明時,就覺得這是一個匿名對象,匿名類型的對象是必須用var 來聲明,但是用var 聲明的對象不一定都是匿名對象,例如 var n=5; 你就不能說n 是一個匿名對象,n只是一個隱式類型化的局部變量;而 var  s=new{ S1="abc",S2="def"}; s 則是一個 類型為匿名類型的對象。也就是說 匿名對象是 用var 聲明的一個 在內存中臨時的類型的對象。它的類型不能像隱式類型那樣根據右邊的實例畫表達式來推斷類型,它是一個實實在在的匿名類型,而var i=5; 這種隱式類型的聲明,編譯時,i其實還是 int32 類型,隱式類型只是一種語法糖。

 

那匿名類型一般都在什么情況下使用呢?
           1.匿名類型通常用在查詢表達式的 select 子句中,以便返回源序列中每個對象的屬性子集(Linq 中使用的比較多)
           匿名類型包含一個或多個公共只讀屬性。 包含其他種類的類成員(如方法或事件)為無效。 用來初始化屬性的表達式不能為 null、匿名函數或指針類型。
           最常見的方案是用其他類型的屬性初始化匿名類型。在下面的示例中,假定名為 Product 的類存在。 Product 包括 ColorPrice 屬性,以及您不感興趣的其他屬性。 變量                  productsProduct 對象的集合。 匿名類型聲明以 new 關鍵字開始。 聲明初始化了一個只使用 Product 的兩個屬性的新類型。 這將導致在查詢中返回較少數量的數據。
           如果您沒有在匿名類型中指定成員名稱,編譯器會為匿名類型成員指定與用於初始化這些成員的屬性相同的名稱。 必須為使用表達式初始化的屬性提供名稱,如下面的示例所示。 在下            面示例中,匿名類型的屬性名稱都為 ColorPrice          

 

var  productQuery =  from prod  in products

                  select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

上面的查詢中使用一個匿名對象保存了查詢的結果。 new { prod.Color,prod.Price} 匿名類型,會使用 查詢結果prod 對象的Color屬性和Price屬性作為新的匿名對象的屬性。

 

可通過將隱式鍵入的本地變量與隱式鍵入的數組相結合創建匿名鍵入的元素的數組,如下面的示例所示。

 var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};

上面的代碼是將兩個匿名對象存入一個匿名的數組中。需要注意的是,在上面代碼中,匿名數組存儲的匿名對象的初始化器里的屬性類型和屬性名稱和屬性的數量必須一致。也就是說

new { name = "apple", diam = 4 }=new { name = "grape", diam = 1 } 成立的條件是: 屬性名字和屬性存儲的值的類型以及屬性個數必須全部相同,vs  編譯器才會認為這兩個匿名類型是同一個類型。這樣的兩個匿名類型才能夠存入 anonArray 這樣的一個匿名數組中。因為匿名數組也只能存儲同一種類型的匿名對象。

2.擴展方法 

  1.擴展方法(Extension method),可以對現有類功能進行擴充,從而使該類型的實例具有更多的方法(功能)。比如你我從第三方的廠商那里獲取到了一個dll程序集,而我們要對該程序集的類擴充某寫功能,我們就可以使用擴展方法來對該類進行擴充。

  2.Extension Method僅僅是看起來像是一個類型的方法,但其實質上不是,它更像是靜態類型的靜態方法,事實上,它確實擁有靜態方法所具有的所有功能 。這點在下面實現擴展方法的時候就會明白,其實擴展方法就是一靜態方法。

  3.Extension Method的作用域是整個namespace可見的,並且可以通過using namespace來導入其它命名空間中的Extension Method 
  4.編譯器生成的中間語言(IL) 會將代碼轉換為對靜態方法的調用。因此,並未真正違反封裝原則。
  5.實際上,擴展方法無法訪問它們所擴展的類型中的私有變量。

約定:
  1.可以使用擴展方法來擴展類或接口,但不能重寫擴展方法。

  2.與接口或類方法具有相同名稱和簽名的擴展方法永遠不會被調用。

  3.編譯時,擴展方法的優先級總是比類型本身中定義的實例方法低。

    換句話說,如果某個類型具有一個名為Process(int i) 的方法,而您有一個具有相同簽名的擴展方法,則編譯器總是綁定該實例方法。

  4.當編譯器遇到方法調用時,它首先在該類型的實例方法中尋找匹配的方法。

    如果未找到任何匹配方法,編譯器將搜索為該類型定義的任何擴展方法,並且綁定到它找到的第一個擴展方法

  MSDN中是這么定義的:

 擴展方法使您能夠向現有類型“添加”方法,而無需創建新的派生類型、重新編譯或以其他方式修改原始類型。擴展方法是一種特殊的靜態方法,但可以像擴展類型上的實例方法一樣進行調用。

 Smaple:
    1 namespace Demo

 2 {
 3      class Program
 4     {
 5          static  void Main( string[] args)
 6         {
 7              var stu =  new Student() { Name =  " joey ", Age =  25 };
 8              // 調用實例方法
 9              Console.WriteLine(stu.ToString());
10              // 調用擴展方法 。調用的時候會vs 智能感知會在方法邊上加個向下的箭頭,表示這是一個擴展方法
11              Console.WriteLine(stu.Hello());
12         }
13     }
14      public  class Student
15     {
16          public  string Name {  getset; }
17          public  int Age {  getset; }
18          // 重寫ToString方法
19           public  new  string ToString()
20         {
21              return  " Name:  " +  this.Name +  " \nAge:  " +  this.Age;
22         }
23     }
24 
25      public  static  class ExtendMehods
26     {
27          // 使用this 關鍵字擴展類的方法
28           public  static  string Hello( this Student stu)
29         {
30              return  " 嗨!大家好!我叫  " + stu.Name +  " ,我今年  " + stu.Age +  "  歲 ";
31         }
32     }
33 }
其實擴展方法就是一個靜態非泛型類中的一個靜態方法。我們也可以使用靜態類名點方法名的方式調用。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM