為了使LINQ可以無縫的和C#語言整合在一起,微軟對C#3.0加入了些新功能,這裡主要介紹和LINQ相關 的加強。
1、var關鍵字,集合初始化以及匿名類型
2、Lambda 表達式
3、部分(Partial )方法
4、擴展方法
5、表達式樹
1、var關鍵字,集合初始化以及匿名類型
var:
可以賦予局部變量推斷“類型”var 而不是顯式類型。var 關鍵字指示編譯器根據初始化語句右側的 表達式推斷變量的類型。推斷類型可以是內置類型、匿名類型、用戶定義類型、.NET Framework 類庫中 定義的類型或任何表達式。var只是表示由編譯器確定和分配最適當的類型。和javascript中的var的概念 不同.例如:var i = 5;編譯完之後i就是一個整型,和int i=5;沒有任何區別.在很多情況下,var 是可選 的,它只是提供了語法上的便利。
請看如下例子:
var i = 5;//int
var j = 23.56;//double
var k = "C Sharp";//string
var x;// 錯誤
var y = null;//錯誤
var z = { 1, 2, 3 };//錯誤
對象和集合初始值設定項:
class user
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
User user = new User ();
user.Id = 1;
user.Name = “lfm";
user.Age = 22;
在VS2008中,編譯器 會自動地生成合適的屬性setter代碼,使得原來幾行的屬性賦值操作可以在一行完成。我們可以這樣簡化 :像這樣,對象初始化器由一系列成員對象組成,其對象必須初始化,用逗號間隔,使用{}封閉。
User user = new User { Id = 1, Name = “lfm", Age = 22 };
又例如,我把二個人加到一個基於泛型的類型為User的List集合中:
List<User> user = new List<User>{
new User{Id=1,Name= “lfm",Age=22},
new User{Id=2,Name=“tmx",Age=25},
};
匿名類型:
匿名類型提供了一種方便的方法,可用來將一組只讀屬性封裝到單個對象中,而無需首先顯式定義一 個類型。類型名由編譯器生成,並且不能在源代碼級使用。這些屬性的類型由編譯器推斷。
匿名類型允許定義行內類型,無須顯式定義類型。在將匿名類型分配給變量時,必須使用 var 構造初 始化該變量。
//屬性也不需要申明,這些屬性的類型由編譯器推斷
var p1 = new { Id = 1, Name = “lfm", Age = 22 };
var p2 = new { Id = 2, Name = “tmx", Age = 25 };
p1 = p2;//p1,p2結構相同,可以互相賦值
在這裡編譯器會認為p1,p2相當於:
public class SomeType
備注(from msdn)
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
匿名類型是直接從對象派生的引用類型。盡管應用程序無法訪問匿名類型,但編譯器仍會為其提供一 個名稱。從公共語言運行庫的角度來看,匿名類型與任何其他引用類型沒有什麼不同。
如果兩個或更多個匿名類型以相同的順序具有相同數量和種類的屬性,則編譯器會將這些匿名類型視 為相同的類型,並且它們共享編譯器生成的相同類型信息。
匿名類型具有方法范圍。若要向方法邊界外部傳遞一個匿名類型或一個包含匿名類型的集合,必須首 先將匿名類型強制轉換為對象。但是,這會使匿名類型的強類型化無效。如果必須存儲查詢結果或者必須 將查詢結果傳遞到方法邊界外部,請考慮使用普通的命名結構或類而不是匿名類型。
2、Lambda 表達式
在c#3.0中微軟加入了“Lambda 表達式”,“Lambda 表達式”的概念最早是數學家Alonzo Church在 1936年提出的,早在LISP語言中就已經得到應用。這些表達式提供了簡短的語法來表達一個運算法則。在 C#3.0中“Lambda 表達式”是一個匿名函數,它可以包含表達式和語句,並且可用於創建委托或表達式目 錄樹類型。在我們詳細講解“Lambda 表達式”之前,我們先來了解一下“Lambda 表達式”出現的原因。
我們假設這樣一個場景,我們希望有這樣一個函數,對一個整型數組進行過濾,而過濾得條件在編寫 函數時還不知道,直到使用這個函數的時候可以根據當前的情況編寫過濾條件函數,大家一看到這個場景 可能馬上想到,可以使用委托阿。ok,代碼如下:
public class Common
{
public delegate bool IntFilter(int i);
public static int[] FilterArrayOfInts(int[] ints, IntFilter filter)
{
ArrayList aList = new ArrayList();
foreach (int i in ints)
{
if (filter(i))
{
aList.Add (i);
}
}
return ((int[])aList.ToArray (typeof(int)));
}
}
public class Application
{
public static bool IsOdd(int i)
{
return ((i & 1) == 1);
}
}
static void Main (string[] args)
{
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] oddNums = Common.FilterArrayOfInts(nums, Application.IsOdd);
foreach (int i in oddNums)
Console.WriteLine(i);
}
結果為:
1
3
5
7
9
看了這段代碼之後,大家可能會覺得這個實現可能不夠好,這裡的IsOdd函數可能只用這麼一次,並且 也太簡單了,不值得當成一個函數來用,於是我們想到了C#2.0的匿名委托,實現代碼如下:
static void Main(string[] args)
{
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] oddNums =
Common.FilterArrayOfInts(nums, delegate(int i) { return ((i & 1) == 1); });
foreach (int i in oddNums)
Console.WriteLine(i);
}
恩,這段代碼似乎相當棒了,解決了我剛才說的所有問題,但是看起來好象不夠簡潔, 也比較難懂些。我希望有一個更好的方式來解決這個問題。
我們先來看看“Lambda 表達式”的用法,所有 Lambda 表達式都使用 Lambda 運算符 =>,該運算 符讀為“goes to”。該 Lambda 運算符的左邊是輸入參數(如果有),右邊包含表達式或語句塊。 Lambda 表達式 x => x * x 讀作“x goes to x 乘x”其意義就是輸入x返回x乘x。
Lambda 表達式返回表達式的結果,並采用以下基本形式:
(input parameters) => {statement;}
多個參數時可以使用如下方式
(param1, param2, …paramN) => expr
更為復雜的方式可以如下表示
(param1, param2, …paramN) =>
這裡大家需要知道的是“Lambda 表達式”其實就是一個匿名委托,可以使用“Lambda 表達式”的地方必 須是可以使用委托的地方,Lambda 運算符 =>左邊的是輸入參數,Lambda 運算符 =>右邊的部分是 執行後的輸出結果
{
statement1;
statement2;
…
statementN;
return(lambda_expression_return_type);
}
比如
x => x.Length > 0
相當於
delegate(string x) { return x.Length > 0; }
大家理解了“Lambda 表達式”,我們就可以使用“Lambda 表達式”來完成剛才過濾數據的場景了。 代碼如下:
static void Main(string[] args)
{
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] oddNums = Common.FilterArrayOfInts(nums, i => ((i & 1) == 1));
foreach (int i in oddNums)
Console.WriteLine(i);
}
這段代碼比剛才匿名委托的方式易讀性要好很多了吧