.net版本發展歷程:
| 版本 | 版本號 | 發布日期 | Visual Studio | windows集成 |
|---|---|---|---|---|
| 1.0 | 1.0.3705.0 | 2002-02-13 | Visual Studio .NET | |
| 1.1 | 1.1.4322.573 | 2003-04-24 | Visual Studio .NET 2003 | Windows Server 2003 |
| 2.0 | 2.0.50727.42 | 2005-11-07 | Visual Studio 2005 | |
| 3.0 | 3.0.4506.30 | 2006-11-06 | Windows Vista, Windows Server 2008 | |
| 3.5 | 3.5.21022.8 | 2007-11-19 | Visual Studio 2008 | Windows 7, Windows Server 2008 R2 |
| 4.0 | 4.0.30319.1 | 2010-04-12 | Visual Studio 2010 |
.NET Framework 各個版本之間的關系圖:

C#2.0新特性:
一、泛型(Generic)
概述:
引入泛型絕對是C#2.0的最大的新特性。通過“參數化類型”實現一份代碼操作多種數據類型。泛型的優點是更好的類型安全;更好的復用;更高的效率和更清晰的約束。但說實在,除了一些通用的數據結構,集合類和通用算法外,使用到泛型的地方還不多。而且System.Collections.Generic中的類也很夠用了。基本沒寫過自己的泛型類。
語法點:
語法方面主要是使用在類型名稱后面加入“<T>”來傳入類型參數。涉及泛型類型繼承的一條規則是“封閉類(所有類型都已確定)不能繼承開放類(含有未確定類型)”。同時可以使用where來添加對作為參數的類型的約束。具體有四種:基類約束、接口約束、構造器約束和值/引用類型約束。最后特別提醒,delegate也是一種類型,別忘了泛型委托。
二、泛型方法(Generic Method)
概述:
泛型方法即在方法聲明中包含類型參數。其實屬泛型的內容。但泛型方法可以用在一般類中。
語法點:
重載(overload)的時候注意,約束不成為方法簽名的一部分。而重寫(override),約束是會被默認繼承的。
三、匿名方法(Anonymous Method)
概述:可以直接將代碼賦給委托。在進行委托實例化時可以省略掉委托類型。代碼示例如下:
myButton.Click += delegate {//代碼}
myButton.Click += myClick;
感覺就是一種語法的簡化。從代碼的可維護性來說還是不用為好。但又確實能使一些代碼簡潔一點。看團隊的決定吧。
語法點:
要注意外部變量的生存周期會一直延長到委托實例引用結束。盡量避免使用。
四、迭代器(Iterator)
概述:
嚴格來說只是簡化迭代器的構造罷了。或者說簡化了創建可以用於foreach的枚舉集合的工作。通過引入關鍵字yield來實現。再不用太多的關心IEnumerator了。直接在類中實現GetEnumerator()然后在for循環中用yield return就可以了。
語法點:
可以用yield break來停止迭代。
五、局部類(Partial Class)
概述:
就是允許通過關鍵字partial將一個類寫在多個cs文件中。最大的用處可能就是將IDE自動生成的代碼分開吧。大家都留意到VS05中的自動生成的代碼都到designer.cs中去了吧。
語法點:
在不同部分定義中,Attribute和Interface是累加的。當然要保證基類的唯一。而abstract和sealed是部分使用,整個類生效。語義類型訪問修飾符要保持一致。
六、可空類型(Nullable Type)
概述:
其實是一個泛型類型。System.Nullable<T>,T必須為值類型。並且通過“?”來作一個語法的簡化。用一句代碼說明就是:
int? x = null;
引入NullableType獲得的啟示是,.Net的ORMapping可以做得更好了。
語法點:
使用HasValue屬性判斷是否為null。
七、靜態類(Static Class)
概述:
可以聲明一個static class。該class不能被繼承不能被實例化,只能包含靜態成員。相當於sealed abstract。用途可以用作全局函數。另外Singleton模式的實現更方便了。
語法點:
不能有constructor,不能有實例成員,不能再使用sealed abstract修飾。不能繼承其他類和實現任何interface。成員不能使用protected修飾符。
八、屬性訪器訪問修飾符
概述:
可以額外對get、set中的其中一個屬性訪問其使用一個訪問修飾符。用途可以說是更靈活的封裝吧。
語法點:
只能在get、set的一個中使用。接口中的屬性訪問器不能同樣不能帶有訪問修飾符。索引器可以使用。
九、命名空間別名限定符
概述:可以使用雙冒號“::”使用一個命名空間的別名。如
using sc=System.Collection;
那么使用的時候就可以寫成sc::ArrayList()了。
作用是更方便的調用不同命名空間下的同名類性。
就寫這主要的九點,其他還有的一些C#2.0的新特就不寫了。因為離開發的使用更遠了。總的來說除了泛型,2.0真的不是有很多的有用的變化。或許更應關注Framework的發展吧。以上的是我個人的歸納,寫得不詳細。如果真的想了解語法各位看官可要自己再查了。2.0已遠處,C#3.0已經來了,一股LINQ的學習熱潮到了。繼續前行,學好新技術,更關鍵是用好新技術。
--------------------------------------------------------------------------------------------------
C#3.0新特性:
1:隱式類型的本地變量和數組
2:對象初始值設定項
3:集合初始值設定項
4:自動實現屬性
5:匿名類型
6:擴展方法
7:分部方法定義
8:Lambda 表達式
關鍵字(var)
1:var可以用局部變量聲明不可以用於字段可以應用於for、foreach、using語句中
2:var關鍵字不能包含自身對象或者集合初始化器,但可以經過new的新表達式
例:var result;//編譯錯誤
var result=result+1;//編譯錯誤
var result={1,2,3};//編譯錯誤
3:var是推斷類型,不是顯示類型
4:var關鍵字指示編譯器根據初始化語句右側的表達式推斷變量的類型
5:推斷類型可以是內置類型、匿名類型、用戶定義類型、.NET Framework 類庫中定義的類型或任何表達式
注:var關鍵字並不意味着“變體”,也不表示該變量時松散類型化變量或后期綁定變量。它只是表示由編譯器確定和分配最適合的類型
var 使用的場景
1:局部變量
例:var i = 5;
2:在for初始化語句
例:for(var i = 1; i < 10; ++i)
3:在foreach初始化語句
例:foreach(var item in list)
4:在using語句
例:using(var file = new StreamReader("C:\"))
一:隱式類型的本地變量和數組
注:隱形數組使用var關鍵字和數組初始化器創建。元素的數據類型必須能夠隱式轉換為同一數據類型,並且不能為空(null)
1:沒有在初始化語句的左側隱式類型的數組使用方括號
2:支持交錯數組,不支持多維數組
例:var a = new [] {1,2,3} //一維數組
var b = new []
{
new [] {1,2,3},
new [] {5,6}
}; //交錯數組
二:對象初始值設定項
注:對象初始化器由一系列成員對象組成,其對象必須初始化,用逗號間隔,使用{}封閉
1.NET 2.0寫法:
User userInfo = new User();
userInfo.ID = “zhuxing”;
userInfo.Name = “czx”;
userInfo.Age= 22;
2.NET 3.5寫法:
User userInfo = new User() {ID = “zhuxing”, Name = “czx”, Age=22};
注:嵌套復雜屬性類型
User userInfo = new User()
{
ID=“zhuxing”,
Name=“czx”,
Address =new Address()
{
Province=“FuJian”,
City=“ningde”
}
};
1:可以和構造函數一起使用,並且構造函數初始化先於對象初始化器執行
2:允許部分賦值
3:允許給internal 成員賦值
public class user
{
public String Name { get; set; }
public String Age { get; set; }
private Int32 test = 25;
internal Int32 test2;
}
public class Program
{
static void Main(string[] args)
{
user person = new user { Name = "張三", Age = "男", test2 = 20 };
Console.WriteLine("{0},{1},{2}",person.Name, person.Age, person.test2);
Console.ReadLine();
}
}
//和構造函數一起使用
public class user
{
public String Name { get; set; }
public Int32 Age { get; set; }
private Int32 test = 25;
internal Int32 test2;
public user(Int32 Age)
{
this.Age = Age;
}
}
public class Program
{
static void Main(string[] args)
{
user person = new user(20) { Name = "張三", Age = 22, test2 = 20 };
Console.WriteLine("{0},{1},{2}",person.Name, person.Age, person.test2);
Console.ReadLine();
}
}
三:集合初始值設定項
注:
1:集合初始化器由一系列集合對象組成,用逗號間隔,使用{}封閉。
2:集合初始化器會對初始化器中的元素進行按序調用ICollection<T>.Add(T)方法
例如:List<int> number=new List<int>{1,2,3,4,5};
//集合初始化器
public class parame
{
public String Name { get; set; }
public Int32 Age { get; set; }
}
public class Program
{
static void Main(string[] args)
{
IList<parame> people = new List<parame>()
{
new parame{ Name = "張三", Age = 18},
new parame{ Name = "李四", Age = 20}
};
foreach (var i in people)//var 是3.0特有的
{
Console.WriteLine("{0},{1}", i.Name, i.Age);
}
Console.ReadLine();
}
}
四:自動實現屬性
1、.NET2.0下寫User類:
public class User
{
private string id;//用戶ID
public string ID
{
get{return id;}
Set {id=value;}
}
private string name;//用戶名稱
public string Name
{
get{return name;}
set{name=value;}
}
}
2、.NET 3.5下寫User類:
public class User
{
public string ID{get;set;}
public string Name{get;set;}
}
注:在VS2008像以上寫法,編譯器自動會為類中生成一個私有變量,並對這個變量實現公開的getter和setter訪問器
五:匿名類型
注:使用new操作符和匿名對象初始化器創建一個新的對象,該對象是匿名類型的對象。
如:
var role=new{ID=“zhuxing”,Name=“czx”};
等同於:
class _Anonymous1
{
private string id;
public string ID
{
get{return id;}
set{id=value;}
}
private string name;
public string Name
{
get{return name;}
set{name=value;}
}
}
1:匿名類型提供了一種方便的方法,可以用來將一組只讀屬性封裝到單個對象中,而無需首先顯示定義一個類型
2:類型名由編譯器生成,並且不能在源代碼級使用
3:這些屬性的類型由編譯器判定
4:匿名類型通常用在查詢表達式select子句中,以便返回源序列化對象的屬性子集
5:匿名類型是使用new運算符和對象初始值設定項創建的
6:匿名類型是由一個或多個只讀屬性組成的類類型。不允許包含其他種類的類型
(如方法或事件)
7:匿名類型是直接從對象派生的引用類型。盡管應用程序無法訪問匿名類型,但編譯器仍會為其提供一個名稱。
8:如果兩個或更多個匿名類型以相同的順序具有相同數量和種類的 如果兩個或更多個匿名類型以相同的順序具有相同數量和種類的屬性,則編譯器會將這些匿名類型視為相同的類型,並且它們共享編譯器生成的相同類型信息。匿名類型具有方法范圍 – 匿名類型具有方法范圍。
9:匿名類型不能像屬性一樣包含不安全類型。
10:由於匿名類型上的 Equals 和 GetHashCode 方法是根據屬性的 由於匿名類型上的Equals 和 GetHashCode 方法是根據屬性的Equals 和 GetHashcode 定義的,因此僅當同一匿名類型的兩個
注:查詢表達式經常使用匿名類型,而這些類型只能使用對象初始值設定項進行初始化
例:var productInfos = from p in products
select new { p.ProductName, p.UnitPrice };
創建匿名類型時重命名字段:
select new {p.ProductName, Price = p.UnitPrice};
六:擴展方法
1、擴展方法的優勢
1.1、允許開發人員往一個現有的CLR類型的公開契約(contract)中添加新的方法,而不用生成子類或者重新編譯原來的類型。
1.2、可以通過使用實例方法語法調用的靜態方法 ,對現有類功能進行擴充,從而使該類型的實例具有更多的方法(功能)。
1.3、允許我們在不改變源代碼的情況下擴展(即添加不能修改)現有類型中的實例方法
1.4、有助於把今天動態語言中流行的對duck typing的支持之靈活性,與強類型語言之性能和編譯時驗證融合起來
2、擴展方法的要點
2.1、本質為將實例方法調用在編譯期改變為靜態類中的靜態方法調用,具備靜態方法的功能
2.2、作用域是整個namespace可見的,並且可以通過using namespace來導入其它命名空間中的擴展方法。
2.3、優先級:現有實例方法優先級最高,其次為最近的namespace下的靜態類的靜態方法,最后為較遠的namespace下的靜態類的靜態方法
七:分部方法定義
注:處理一些輕量級的事件
八:Lambda 表達式
1、格式如下:(參數列表)=>表達式或語句塊 ;
例: var str=list.FindAll(s=>s.indexof(“mzc”)>=0);
2、參數列表可以是顯示或者隱式類型,在顯式列表中,每個參數的類型是顯式指定的,在隱式列表中,參數的類型由Lambda表達式出現的語境自動推斷類型 。
例:
(x, y) => x * y;//多參數,隱式類型=>表達式
x => x * 10;//單參數,隱式類型=>表達式
x => { return x * 10; }; //單參數,隱式類型=>語句塊
(int x) => x * 10;//單參數,顯式類型=>表達式
(int x) => { return x * 10; };//單參數,顯式類型=>語句塊
( ) => Console.WriteLine(); //無參數
表達式樹
注:表達式樹允許像處理數據一樣對Lambda表達式進行讀取和改寫,比如我們在動態查詢的時候經常應用到
------------------------------------------------------------------------------------------------------
C#3.5新特性:
Visual Studio 2008和.NET 3.5是建立在.NET2.0核心的基礎之上,C# 3.0新語言特性在.NET2.0基礎上進行了改進,這些改進的功能可以大大簡化我們編寫程序。在此為了自己學習記錄下來,並與大家分享
.NET 3.5的新特性包括:
自動屬性(Auto-Implemented Properties)
隱含類型局部變量(Local Variable Type Inference)
匿名類型(Anonymous Types)
對象與集合初始化器(Object and Collection Initializers)
擴展方法(Extension Methods)
Lambda表達式和Lambda表達式樹 (Lambda Expression and Lambda Expression Trees)
LINQ,語言級集成查詢(Language INtegrated Query)
自動屬性(Auto-Implemented Properties)
自動屬性可以避免原來這樣我們手工聲明一個私有成員變量以及編寫get/set邏輯,在VS2008中可以像下面這樣編寫一個類,編譯器會自動地生成私有變量和默認的get/set 操作。你也可以分別定義get和set的"protected"等訪問級別。
在.Net2.0框架下,我們可以這樣寫一個User類:
public class User
{
private int _id;
private string _name;
private int _age;
public int Id
{
get { return _id; }
set { _id = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public int Age
{
get { return _age; }
set { _age = value; }
}
}現在,可以這樣簡化:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
我們可以利用VS.NET提供的ildasm進行反編譯,可以發現.NET幫我定義了私有變量,在此不再贅言。
隱含類型局部變量(Local Variable Type Inference)
C#3.0引進了var這個新關鍵字,在聲明局部變量時可用於替代原先的類型名,即當一個變量聲明標識為var類型並且該范圍域中沒有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 };//錯誤
注意事項:
必須對var聲明的變量賦值,因為C#中的var並不等同於VB於Javascript中的var,后者中 的var為一種變量類型,而在C#中var並不是一種類型,它只用來隱式的聲明變量,而你定義的變量類型由編譯器判斷;
Var聲明的變量不能賦null;
Var只能聲明局部變量;
不允許,改變var變量的類型
Var x = 100;
X = "Hello world!"
由此可知,var的變量也是強類型的變量,具有安全性。
匿名類型(Anonymous Types)
匿名類型允許定義行內類型,無須顯式定義類型。常和var配合使用來聲明匿名類型。
var p1 = new { Id = 1, Name = "tony", Age = 21 };//屬性也不需要申明
var p2 = new { Id = 2, Name = "dream", Age = 21 };
var p3 = new { Id =3 , age = 21, Name = "tony"}
p1 = p2;//p1,p2結構相同,可以互相賦值 ,p1與p3不是相同的對象,所以使用匿名類型時我們盡量將具有相同屬性的變量,屬性的順序保持一致。
在這里編譯器會認為p1,p2相當於:
public class SomeType
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}那么數組怎么定義呢?使用"new[]"關鍵字來聲明數組,加上數組的初始值列表。像這樣:
var intArray = new[] { 2, 3, 5, 6 };
var strArray = new[] { "Hello", "World" };
var anonymousTypeArray = new[]
{
new { Name = "tony", Age = 21 },
new { Name = "dream", Age = 22 }
};
var a = intArray[0];
var b = strArray[0];
var c = anonymousTypeArray[1].Name;
可以使用new關鍵字調用匿名初始化器創建一個匿名類型的對象。
匿名類型直接繼承自System. Object。
匿名類型的成員是編譯器根據初始化器推斷而來的一些讀寫屬性。
對象初始化器 (Object Initializers) :
.NET2.0框架中的類型非常依賴於屬性。當生成對象實例和使用新的類型時,在.Net2.0時候我們像這樣寫:
User user = new User();
user.Id = 1;
user.Name = "tony";
user.Age = 22;在VS2008中,編譯器會自動地生成合適的屬性setter代碼,使得原來幾行的屬性賦值操作可以在一行完成。我們可以這樣簡化:像這樣,對象初始化器由一系列成員對象組成,其對象必須初始化,用逗號間隔,使用{}封閉。
User user = new User { Id = 1, Name = "tony", Age = 21 };又例如,我把二個人加到一個基於泛型的類型為User的List集合中:
List<User> user = new List<User>{
new User{Id=1,Name="tony",Age=21},
new User{Id=2,Name="dream",Age=12},
};
如果有相同名字和類型的兩個對象初始化器將會產生相同的實例,可以相互賦值。例如:
User user = new User { Id = 1, Name = "tony", Age = 21 };
User user2 = new User { Id = 2, Name = "tony", Age = 12 };
user = user2;
除了在初始化類時設置簡單的屬性值外,對象初始化器特性也允許我們設置更復雜的嵌套(nested)屬性類型。例如我們可以在上面定義的User類型同時擁有一個屬於School類型的叫"School"的屬性:
User user = new User
{
Id = 1,
Name = "tony",
Age = 21,
School = new School
{
City = "Beijing",
Name = "BTBU"
}
};
集合初始化器(Collection Initializers):
集合初始化器由一系列集合對象組成,用逗號間隔,使用{}封閉。
集合初始化器可以簡化把幾個對象一起添加到一個集合,編譯器會自動為你做集合插入操作。例如我把七個數加到一個基於泛型的類型為int的List集合中
List<int> num = new List<int> { 0, 1, 2, 6, 7, 8, 9 };對象與集合初始化器要點
對象初始化器實際上利用了編譯器對對象中對外可見的字段和屬性進行按序賦值。
對象初始化器允許只給一部分屬性賦值,包括internal訪問級別
對象初始化器可以結合構造函數一起使用,並且構造函數初始化先於對象初始化器執行。
集合初始化器會對初始化器中的元素進行按序調用ICollection<T>.Add(T)方法,所以只有具有Add方法的類才可以使用這種方法添加一個元素,例如ArrayList等,例如HashTable,字典等就不支持這種添加方式,因為其存在key,value兩個值。
注意對象初始化器和集合初始化器中成員的可見性和調用順序。
對象與集合初始化器同樣是一種編譯時技術。
擴展方法(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 = "tony", Age = 21 };
var str = user.Read();現在有了擴展方法就方便多了。
擴展方法允許開發人員往一個現有的CLR類型的公開契約(contract)中添加新的方法,而不用生成子類或者重新編譯原來的類型。擴展方法有助於把今天動態語言中流行的對duck typing的支持之靈活性,與強類型語言之性能和編譯時驗證融合起來。
擴展方法是可以通過使用實例方法語法調用的靜態方法。效果上,使得附加的方法擴展已存在類型和構造類型成為可能。他可以對現有類功能進行擴充,從而使該類型的實例具有更多的方法(功能)。
擴展方法允許我們在不改變源代碼的情況下擴展(即添加不能修改)現有類型中的實例方法。
擴展方法給我們一個怎樣的思路呢?我們一步一步做一下!
首先聲明擴展方法:通過指定關鍵字this修飾方法的第一個參數。注意擴展方法僅可聲明在靜態類中。擴展方法具備所有常規靜態方法的所有能力,可以使用實例方法語法來調用。接着就可以調用擴展方法了。下面通過一個具體的實例分析一下:
例如我們要檢查一個字符串變量是否是合法的電子郵件地址?在.Net2.0框架下像這樣:
var email = "390534711@qq.com";
if (EmailValidator.IsValid(email))
{
Response.Write("tony提示:這是一個正確的郵件地址");
}而使用擴展方法的話,我可以添加"IsValidEmailAddress()"方法到string類本身中去,該方法返回當前字符串實例是否是個合法的字符串。
if (email.IsValidEmailAddress())
{
Response.Write("tony提示:這是一個正確的郵件地址");
}我們是怎么把這個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下的靜態類的靜態方法。
擴展方法是一種編譯時技術,注意與反射等運行時技術進行區別,並慎重使用。
Lambda表達式和Lambda表達式樹 (Lambda Expression and Lambda Expression Trees)
Lambda表達式
我們從"所有字符串查找包含tony子字符串"說起。在C# 2.0中,匿名方法允許我們以內聯的方式來實現委托實例,它提供強大的函數式編程語言,但是標記顯得相當的冗長和帶有強制性。我們使用C# 2.0 中的匿名方法查找,代碼如下:
var inString = list.FindAll(delegate(string s)
{ return s.Indexof("tony") >= 0; });現在可以使用C# 3.0帶來的Lambda表達式允許我們使用一種更接近人的思維、更自然的方式來實現類似於匿名方法同樣的效果,看下面的代碼多么簡潔:
var inString = list.FindAll(s => s.Indexof("tony") >= 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="tony",Age=21},
new User{Id=2,Name="tony",Age=22},
};
//獲取特定人時所用的過濾條件,p參數屬於User類型
var results = user.Where(p => p.Name == "tony").ToList();
//用User對象的Age值計算平均年齡
var average = user.Average(p => p.Age);
LINQ,語言級集成查詢(Language INtegrated Query)
經過了最近 20 年,面向對象編程技術( object-oriented (OO) programming technologies )在工業領域的應用已經進入了一個穩定的發展階段。程序員現在都已經認同像類(classes)、對象(objects)、方法(methods)這樣的語言特性。考察現在和下一代的技術,一個新的編程技術的重大挑戰開始呈現出來,即面向對象技術誕生以來並沒有解決降低訪問和整合信息數據(accessing and integrating information)的復雜度的問題。其中兩個最主要訪問的數據源與數據庫( database )和 XML 相關。
LINQ 提供了一條更常規的途徑即給 .Net Framework 添加一些可以應用於所有信息源( all sources of information )的具有多種用途( general-purpose )的語法查詢特性( query facilities ),這是比向開發語言和運行時( runtime )添加一些關系數據( relational )特性或者類似 XML 特性( XML-specific )更好的方式。這些語法特性就叫做 .NET Language Integrated Query (LINQ) 。
包含 DLinq 和 XLinq
C#3.0 LINQ 查詢語法
首先來看一個很簡單的LINQ查詢例子,查詢一個int 數組中小於5的數字,並按照大小順序排列:
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 8, 5, 89, 3, 56, 4, 1, 58 };
var m = from n in arr where n < 5 orderby n select n;
foreach (var n in m)
{
Console.WriteLine(n);
}
Console.ReadLine();
}
}
上述代碼除了LINQ查詢語法外,其他都是我們所熟悉的語法,而LINQ查詢語法跟SQL查詢語法很相似,除了先后順序。
Q:為何 LINQ 查詢語法是以 from 關鍵字開頭的,而不是以 select 關鍵字開頭的?select 開頭這種寫法跟SQL的寫法更接近,更易懂呀?
A:簡單來說,為了IDE的智能感知(InteliSence)這個功能,select 關鍵字放在后面了。
編程語言以 select 開頭寫LINQ查詢語法不是沒出現過,你如果使用過2005年的VB9 CTP 版本,那時候VB9的LINQ查詢語法就是 select 關鍵字在前面,但是 select 關鍵字在前面,在做智能感知(InteliSence)時候就很頭大。經過微軟IDE組的權衡,確定了把 from 關鍵字放在最前面。
我們再來看一個稍稍復雜的LINQ查詢:
在我們羅列的語言字符串中,我們希望按照字符長短,分類羅列出來,實現代碼如下:
static void Main(string[] args)
{
string [] languages = {"Java","C#","C++","Delphi","VB.net","VC.net","C++ Builder","Kylix","Perl","Python"};
var query = from item in languages
orderby item
group item by item.Length into lengthGroups
orderby lengthGroups.Key descending
select lengthGroups;
foreach (var item in query)
{
Console.WriteLine("strings of length ",item.Key);
foreach (var val in item)
{
Console.WriteLine(val);
}
}
Console.ReadLine();
}
其中的 into 關鍵字表示將前一個查詢的結果視為后續查詢的生成器,這里是跟 group by一起使用的。
LINQ中的Group by不要跟 SQL 中的Group by 混淆,SQL 由於是二維結構,Group by 的一些邏輯受二維結構的約束,無法象 LINQ 中的Group by 這么靈活。
-------------------------------------------------------------------------------------
- 簡介
- C# 4.0
- 動態查找
- 類型
- 動態操作
- 運行時查找
- 示例
- 帶有動態參數的重載解析
- 動態語言運行時
- 已知問題
- 命名參數和可選參數
- 可選參數
- 命名的和可選的實參
- 重載解析
- 互操作特性
- 動態引入
- 無PIA的編譯
- ref 省略ref
- 已知問題
- 變性
- 協變性
- 逆變性
- 限制
- COM Example COM示例
- Relationship with Visual Basic 與Visual Basic的關系
