日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

LINQ之路 2:C# 3.0的语言功能(上)

發(fā)布時間:2024/1/17 C# 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LINQ之路 2:C# 3.0的语言功能(上) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在上一篇的LINQ介紹中,我們已經(jīng)看到了隱式類型變量var,擴(kuò)展方法(extension method)和lambda表達(dá)式的身影。沒錯,他們正是LINQ技術(shù)的基石,是他們讓LINQ的實(shí)現(xiàn)成為可能,并且簡化了LINQ表達(dá)式的書寫。在這一篇中,我將和大家一一探討C#3.0在語言功能上所作的努力,包括:隱式類型局部變量、自動屬性和匿名類型。

?

隱式類型局部變量

C#是強(qiáng)類型語言,意味著我們在聲明變量時必須指定變量的具體類型,比如:

static void DeclareExplicitVars()
{
int myInt = 0;
bool myBool = true;
string myString = "Hello, World!";
}

現(xiàn)在C# 3.0為我們提供了一個新的關(guān)鍵字var,你可以使用它代替正式的數(shù)據(jù)類型名(如int, bool, string)。在使用var關(guān)鍵字時,編譯器會根據(jù)用于初始化局部變量的初始值推斷出變量的數(shù)據(jù)類型。例如,上面的變量聲明可以改為如下代碼:

static void DeclareImplicitVars()
{
// 隱式類型局部變量的聲明方式: var varName = defaultValue;
var myInt = 0;
var myBool = true;
var myString = "Hello, World!";
}

上面兩種方式是等價的,編譯器可以根據(jù)初始值推斷myInt的類型為System.Int32,myBool的類型為System.Boolean,myString的類型為System.String。

除此之外,我們可以對基類庫中的所有類型使用隱式類型,包括數(shù)組、泛型、自定義類型。

public static void DeclareImplicitVars()
{
// declare implicit variables
var numbers = new int[] { 2, 4, 6, 8 };
var persons = new List<Person>();
var car = new SportsCar();

// verify the data type using reflection
Console.WriteLine("numbers is a: {0}", numbers.GetType().Name);
Console.WriteLine("persons is a: {0}", persons.GetType().Name);
Console.WriteLine("car is a: {0}", car.GetType().Name);
}

輸出結(jié)果如下:
???????

var在foreach語句中的使用

在foreach循環(huán)語句中,我們也可以使用隱式類型。正如你希望的那樣,編譯器會推斷出正確的數(shù)據(jù)類型:

static void VarInForeachLoop()
{
var numbers = new int[] { 2, 4, 6, 8 };
foreach (var item in numbers)
{
Console.WriteLine("Item value: {0}", item);
}
}

隱式類型變量的限制

需要注意的是,使用var關(guān)鍵字時會存在多種限制。首先,隱式類型只能應(yīng)用與方法或者屬性內(nèi)局部變量的聲明,不能使用var來定義返回值、參數(shù)的類型或類型的數(shù)據(jù)成員。

其次,使用var進(jìn)行聲明的局部變量必須賦初始值,并且不能以null作為初始值。其原因在于編譯器必須能夠根據(jù)初始值推斷出該變量的實(shí)際類型。

隱式類型數(shù)據(jù)是強(qiáng)類型數(shù)據(jù)

隱式類型局部變量最終會產(chǎn)生強(qiáng)類型數(shù)據(jù)。因此,var關(guān)鍵字與腳本語言(如VBScript或Perl)的Variant數(shù)據(jù)類型是不一樣的,對后者來說,一個變量可以在其生命周期中保存不同類型的值。

其實(shí),類型推斷保持了C#語言的強(qiáng)類型特性,并且在編譯時只影響變量聲明。初始化之后,編譯器就已經(jīng)為隱式類型變量推斷出了確切的數(shù)據(jù)類型。如果把不同類型的值賦給變量會導(dǎo)致編譯時錯誤:

static void ImplicitTypingStrongTyping()
{
// 編譯器知道 s 是System.String類型
var s = "This variable can only hold string data!";
s = "It's OK.";

// 可以調(diào)用任何基礎(chǔ)方法
string upper = s.ToUpper();

// 錯誤!不能把數(shù)值類型數(shù)據(jù)賦給String類型變量
s = 100;
}

隱式類型局部變量的作用

看了上面的介紹,你肯定會奇怪這個結(jié)構(gòu)有什么用呢。如果只是為了簡單,就不值得了,因?yàn)檫@樣做可能會使其他閱讀代碼的人感到疑惑。但當(dāng)我們使用LINQ時,var關(guān)鍵字的優(yōu)勢就顯現(xiàn)出來了。它可以動態(tài)根據(jù)查詢本身的格式來創(chuàng)建結(jié)果集,這樣我們就不需要顯示定義查詢可能返回的類型,而且在很多時候我們并不能一眼就看出LINQ的返回類型。如下例:

public static void QueryOverInts()
{
int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 5 };
var subset = from i in numbers where i < 10 select i;

Console.Write("values in subset: ");
foreach (var i in subset)
Console.Write("{0} ", i);
Console.WriteLine();

Console.WriteLine("subset is a: {0}", subset.GetType().Name);
Console.WriteLine("subset is defined in: {0}", subset.GetType().Namespace);
}

輸出:
???????

?其實(shí),我們可以認(rèn)為只有在定義從LINQ查詢返回的數(shù)據(jù)時才使用var關(guān)鍵字。

?

自動屬性

我們知道.NET語言推薦使用類型屬性來封裝私有數(shù)據(jù)字段,而不是 使用GetXXX()和SetXXX()方法。因?yàn)?NET基類庫總是使用類型屬性而不是傳統(tǒng)的訪問和修改方法,因此使用屬性可以獲得與.NET平臺更好的集成性。需要知道的是,在底層,C#屬性會被映射到前綴get_和set_的方法中,即如果定義了Name屬性,C#會自動生成get_Name()和set_Name()方法。

考慮如下的C#類型定義:

class Person
{
private string firstName = string.Empty;
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}

private string lastName = string.Empty;
public string LastName
{
get { return lastName; }
set { lastName = value; }
}

private int level = 0;
public int Level
{
get { return level; }
set { level = value; }
}
}

雖然定義屬性不難,但如果屬性只是賦值和返回值,對次定義字段和屬性也很麻煩,特別是在類屬性很多的情況下。為了簡化這種簡單的數(shù)據(jù)字段封裝的過程,C# 3.0提供了自動屬性語法。現(xiàn)在,上面的Person可以定義成如下形式:

class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Level { get; set; }
}

定義自動屬性時,我們只需要指定訪問修飾符、數(shù)據(jù)類型、屬性名稱和空的get/set作用域。在編譯時,會使用自動生成的私有支持字段以及get/set邏輯的正確實(shí)現(xiàn)。

需要注意的是,定義自動屬性時,必須同時提供get和set關(guān)鍵字,因此不能定義只讀或者只寫的自動屬性。

?

匿名類型

作為一個面向?qū)ο蟮某绦騿T,我們知道如何定義類來表達(dá)一個給定的編程實(shí)體。當(dāng)我需要一個在項(xiàng)目之間重用的類型時,我們通常創(chuàng)建一個C#類,為該類提供必需的一系列屬性、方法和事件等。但有時候,我們可能需要定義類來封裝一些相關(guān)數(shù)據(jù),而不需要任何相關(guān)聯(lián)的方法、事件。并且,給類不需要在項(xiàng)目間重用。盡管如此,我們還是得定義一個“臨時”類,雖然工作不是很復(fù)雜,但是如果需要定義類來封裝很多數(shù)據(jù)成員的話,那么將消耗你大量的勞動時間。我想,大家都不會希望把編程變成一項(xiàng)機(jī)械運(yùn)動吧。

C# 3.0提供的匿名類型正是為了上述任務(wù)而生,匿名類型是匿名方法的自然延伸,可以幫助我們輕松的完成上面的工作。

定義一個匿名類型時,使用新的關(guān)鍵字var和之前介紹的對象初始化語法,如下示例:

static void TestAnonymousType()
{
// 構(gòu)造一個匿名對象表示一個雇員
var worker = new { FirstName = "Vincent", LastName = "Ke", Level = 2 };

// 顯示并輸出
Console.WriteLine("Name: {0}, Level: {1}", worker.FirstName + "" + worker.LastName, worker.Level);
}

使用上述代碼來構(gòu)建匿名對象時,C#編譯器會在編譯時自動生成名稱唯一的類。因?yàn)檫@個類的名字在C#中是不可見的,所以必需使用var關(guān)鍵字來使用隱式類型化。另外,我們需要通過對象初始化語法來定義一系列屬性來封裝各個數(shù)據(jù)。

匿名類型的內(nèi)部表示

所有的匿名類型都自動繼承自System.Object,我們可以在隱式類型話的worker上面調(diào)用ToString()、GetHashCode()、Equals()、GetType()等方法。

我們可以定義如下方法來查看匿名類型的信息:

static void ReflectAnonymousType(object obj)
{
Console.WriteLine("Type Name: {0}", obj.GetType().Name);
Console.WriteLine("Base Class: {0}", obj.GetType().BaseType);
Console.WriteLine("obj.ToString() = {0}", obj.ToString());
Console.WriteLine("obj.GetHashCode() = {0}", obj.GetHashCode());
}

static void TestAnonymousType()
{
// 構(gòu)造一個匿名對象表示一個雇員
var worker = new { FirstName = "Vincent", LastName = "Ke", Level = 2 };
ReflectAnonymousType(worker);
}

結(jié)果如下:

上例中,worker的類型是<>f__AnonymousType0`3(各版本之中可能會有所不同),匿名類型的類型名完全由編譯器決定。更重要的是,使用對象初始化語法定義的每一個名稱/值對被映射為同名的只讀屬性以及被封裝的私有數(shù)據(jù)成員。

方法ToString()和GetHashCode()的實(shí)現(xiàn)

從上面可以看到,匿名類型直接了System.Object,并且重寫了Equals()、GetHashCode()、ToString()方法。其中ToString()根據(jù)每一個名稱/值對,生成并返回一個字符串,見上圖。

GetHashCode()的實(shí)現(xiàn)使用每一個匿名類型的成員變量來計(jì)算散列值。當(dāng)且僅當(dāng)兩個匿名類型有相同的屬性別且被賦予相同的值時,就會產(chǎn)生相同的散列值,這樣,匿名類型就可以很好的和Hashtable容器一起工作。

匿名類型的相等語義

編譯器重寫的Equals()在判斷對象時使用了基于值的語義,但編譯器并沒有重載(==和!=)相等運(yùn)算符,因此使用==比較兩個匿名對象時,是基于引用的語義!”==”比較引用是對所有類的默認(rèn)行為。如下例:

static void AnonymousTypeEqualityTest()
{
// 構(gòu)建兩個匿名類型,擁有相同的名稱/值對
var worker1 = new { FirstName = "Harry", SecondName = "Folwer", Level = 2 };
var worker2 = new { FirstName = "Harry", SecondName = "Folwer", Level = 2 };

// Equals測試
if (worker1.Equals(worker2))
Console.WriteLine("worker1 equals worker2");
else
Console.WriteLine("worker1 not equals worker2");

// ==測試
if (worker1 == worker2)
Console.WriteLine("worker1 == worker2");
else
Console.WriteLine("worker1 != worker2");

// Type Name測試
if (worker1.GetType().Name == worker2.GetType().Name)
Console.WriteLine("we are both the same type");
else
Console.WriteLine("we are different types");
}

結(jié)果為:

?


?

?

總結(jié)

以上是生活随笔為你收集整理的LINQ之路 2:C# 3.0的语言功能(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。