在說LINQ之前必須先說說幾個重要的C#語言特性
一:與LINQ有關的語言特性
1.隱式類型
(1)源起
在隱式類型出現之前,
我們在聲明一個變量的時候,
總是要爲一個變量指定他的類型
甚至在foreach一個集合的時候,
也要爲遍歷的集合的元素,指定變量的類型
隱式類型的出現,
程序員就不用再做這個工作了。
(2)使用方法
來看下面的代碼:
var a = 1; //int a = 1;
var b = "123";//string b = "123";
var myObj = new MyObj();//MyObj myObj = new MyObj()
上面的每行代碼,與每行代碼後面的註釋,起到的作用是完全一樣的
也就是說,在聲明一個變量(並且同時給它賦值)的時候,完全不用指定變量的類型,只要一個var就解決問題了
(3)你擔心這樣寫會降低性能嗎?
我可以負責任的告訴你,這樣寫不會影響性能!
上面的代碼和註釋裏的代碼,編譯後產生的IL代碼(中間語言代碼)是完全一樣的
(編譯器根據變量的值,推導出變量的類型,才產生的IL代碼)
(4)這個關鍵字的好處:
你不用在聲明一個變量並給這個變量賦值的時候,寫兩次變量類型
(這一點真的爲開發者節省了很多時間)
在foreach一個集合的時候,可以使用var關鍵字來代替書寫循環變量的類型
(5)注意事項
你不能用var關鍵字聲明一個變量而不給它賦值
因爲編譯器無法推導出你這個變量是什麼類型的。
2.匿名類型
(1)源起
創建一個對象,一定要先定義這個對象的類型嗎?
不一定的!
來看看這段代碼
(2)使用
var obj = new {Guid.Empty, myTitle = "匿名類型", myOtherParam = new int[] { 1, 2, 3, 4 } };
Console.WriteLine(obj.Empty);//另一個對象的屬性名字,被原封不動的拷貝到匿名對象中來了。
Console.WriteLine(obj.myTitle);
Console.ReadKey(); new關鍵字之後就直接爲對象定義了屬性,並且爲這些屬性賦值
而且,對象創建出來之後,在創建對象的方法中,還可以暢通無阻的訪問對象的屬性
當把一個對象的屬性拷貝到匿名對象中時,可以不用顯示的指定屬性的名字,這時原始屬性的名字會被“拷貝”到匿名對象中
(3)注意
如果你監視變量obj,你會發現,obj的類型是Anonymous Type類型的
不要試圖在創建匿名對象的方法外面去訪問對象的屬性!
(4)優點
這個特性在網站開發中,序列化和反序列化JSON對象時很有用
3.自動屬性
(1)源起
爲一個類型定義屬性,我們一般都寫如下的代碼: 複製代碼
public class MyObj2
{
private Guid _id;
private string _Title;
public Guid id
{
get { return _id; }
set { _id = value; }
}
public string Title
{
get { return _Title; }
set { _Title = value; }
}
}
複製代碼 但很多時候,這些私有變量對我們一點用處也沒有,比如對象關係映射中的實體類。
自C#3.0引入了自動實現的屬性,
以上代碼可以寫成如下形式:
(2)使用
public class MyObj
{
public Guid id { get; set; }
public string Title { get; set; }
}
這個特性也和var關鍵字一樣,是編譯器幫我們做了工作,不會影響性能的
4.初始化器
(1)源起
我們創建一個對象並給對象的屬性賦值,代碼一般寫成下面的樣子
var myObj = new MyObj();
myObj.id = Guid.NewGuid();
myObj.Title = "allen";
自C#3.0引入了對象初始化器,
代碼可以寫成如下的樣子
(2)使用
var myObj1 = new MyObj() { id = Guid.NewGuid(), Title = “allen” };
如果一個對象是有參數的構造函數
那麼代碼看起來就像這樣
var myObj1 = new MyObj (“allen”) { id = Guid.NewGuid(), Title = “allen” };
集合初始化器的樣例代碼如下:
var arr = new List() { 1, 2, 3, 4, 5, 6 };
(3)優點
我個人認爲:這個特性不是那麼amazing,
這跟我的編碼習慣有關,集合初始化器也就罷了,
真的不習慣用對象初始化器初始化一個對象!
5.委託
(1)使用
我們先來看一個簡單的委託代碼
複製代碼
delegate Boolean moreOrlessDelgate(int item);
class Program
{
static void Main(string[] args)
{
var arr = new List() { 1, 2, 3, 4, 5, 6,7,8 };
var d1 = new moreOrlessDelgate(More);
Print(arr, d1);
Console.WriteLine(“OK”);
var d2 = new moreOrlessDelgate(Less);
Print(arr, d2);
Console.WriteLine("OK");
Console.ReadKey();
}
static void Print(List<int> arr,moreOrlessDelgate dl)
{
foreach (var item in arr)
{
if (dl(item))
{
Console.WriteLine(item);
}
}
}
static bool More(int item)
{
if (item > 3)
{
return true;
}
return false;
}
static bool Less(int item)
{
if (item < 3)
{
return true;
}
return false;
}
}
複製代碼
這段代碼中
<1>首先定義了一個委託類型
delegate Boolean moreOrlessDelgate(int item);
你看到了,委託和類是一個級別的,確實是這樣:委託是一種類型
和class標誌的類型不一樣,這種類型代表某一類方法。
這一句代碼的意思是:moreOrlessDelgate這個類型代表返回值爲布爾類型,輸入參數爲整形的方法
<2>有類型就會有類型的實例
var d1 = new moreOrlessDelgate(More);
var d2 = new moreOrlessDelgate(Less);
這兩句就是創建moreOrlessDelgate類型實例的代碼,
它們的輸入參數是兩個方法
<3>有了類型的實例,就會有操作實例的代碼
Print(arr, d1);
Print(arr, d2);
我們把前面兩個實例傳遞給了Print方法
這個方法的第二個參數就是moreOrlessDelgate類型的
在Print方法內用如下代碼,調用委託類型實例所指向的方法
dl(item)
6.泛型
(1)爲什麼要有泛型
假設你是一個方法的設計者,
這個方法有一個傳入參數,有一個返回值。
但你並不知道這個參數和返回值是什麼類型的,
如果沒有泛型,你可能把參數和返回值的類型都設定爲Object了
那時,你心裏肯定在想:反正一切都是對象,一切的基類都是Object
沒錯!你是對的!
這個方法的消費者,會把他的對象傳進來(有可能會做一次裝箱操作)
並且得到一個Object的返回值,他再把這個返回值強制類型轉化爲他需要的類型
除了裝箱和類型轉化時的性能損耗外,代碼工作的很好!
那麼這些新能損耗能避免掉嗎?
有泛型之後就可以了!
(2)使用
<1>使用簡單的泛型
先來看下面的代碼:
複製代碼
var intList = new List() { 1,2,3};
intList.Add(4);
intList.Insert(0, 5);
foreach (var item in intList)
{
Console.WriteLine(item);
}
Console.ReadKey();
複製代碼
在上面這段代碼中我們聲明瞭一個存儲int類型的List容器
並循環打印出了容器裏的值
注意:如果這裏使用Hashtable、Queue或者Stack等非泛型的容器
就會導致裝箱操作,損耗性能。因爲這些容器只能存儲Object類型的數據
<2>泛型類型
List、Dictionary
from p in db.Employees
select new
{
LastName = p.LastName,
TitleOfCourtesy = p.TitleOfCourtesy
} into EmployeesList
orderby EmployeesList.TitleOfCourtesy ascending
select EmployeesList;