LINQ之路 2:C# 3.0的語言功能(上)
在上一篇的LINQ介紹中,我們已經看到了隱式類型變量var,擴展方法(extension method)和lambda表達式的身影。沒錯,他們正是LINQ技術的基石,是他們讓LINQ的實現成為可能,并且簡化了LINQ表達式的書寫。在這一篇中,我將和大家一一探討C#3.0在語言功能上所作的努力,包括:隱式類型局部變量、自動屬性和匿名類型。
隱式類型局部變量
C#是強類型語言,意味著我們在聲明變量時必須指定變量的具體類型,比如:
static void DeclareExplicitVars()
{
int myInt = 0;
bool myBool = true;
string myString = "Hello, World!";
}
現在C# 3.0為我們提供了一個新的關鍵字var,你可以使用它代替正式的數據類型名(如int, bool, string)。在使用var關鍵字時,編譯器會根據用于初始化局部變量的初始值推斷出變量的數據類型。例如,上面的變量聲明可以改為如下代碼:
static void DeclareImplicitVars()
{
// 隱式類型局部變量的聲明方式: var varName = defaultValue;
var myInt = 0;
var myBool = true;
var myString = "Hello, World!";
}
上面兩種方式是等價的,編譯器可以根據初始值推斷myInt的類型為System.Int32,myBool的類型為System.Boolean,myString的類型為System.String。
除此之外,我們可以對基類庫中的所有類型使用隱式類型,包括數組、泛型、自定義類型。
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);
}
輸出結果如下:

var在foreach語句中的使用
在foreach循環語句中,我們也可以使用隱式類型。正如你希望的那樣,編譯器會推斷出正確的數據類型:
static void VarInForeachLoop()
{
var numbers = new int[] { 2, 4, 6, 8 };
foreach (var item in numbers)
{
Console.WriteLine("Item value: {0}", item);
}
}
隱式類型變量的限制
需要注意的是,使用var關鍵字時會存在多種限制。首先,隱式類型只能應用與方法或者屬性內局部變量的聲明,不能使用var來定義返回值、參數的類型或類型的數據成員。
其次,使用var進行聲明的局部變量必須賦初始值,并且不能以null作為初始值。其原因在于編譯器必須能夠根據初始值推斷出該變量的實際類型。
隱式類型數據是強類型數據
隱式類型局部變量最終會產生強類型數據。因此,var關鍵字與腳本語言(如VBScript或Perl)的Variant數據類型是不一樣的,對后者來說,一個變量可以在其生命周期中保存不同類型的值。
其實,類型推斷保持了C#語言的強類型特性,并且在編譯時只影響變量聲明。初始化之后,編譯器就已經為隱式類型變量推斷出了確切的數據類型。如果把不同類型的值賦給變量會導致編譯時錯誤:
static void ImplicitTypingStrongTyping()
{
// 編譯器知道 s 是System.String類型
var s = "This variable can only hold string data!";
s = "It's OK.";
// 可以調用任何基礎方法
string upper = s.ToUpper();
// 錯誤!不能把數值類型數據賦給String類型變量
s = 100;
}
隱式類型局部變量的作用
看了上面的介紹,你肯定會奇怪這個結構有什么用呢。如果只是為了簡單,就不值得了,因為這樣做可能會使其他閱讀代碼的人感到疑惑。但當我們使用LINQ時,var關鍵字的優勢就顯現出來了。它可以動態根據查詢本身的格式來創建結果集,這樣我們就不需要顯示定義查詢可能返回的類型,而且在很多時候我們并不能一眼就看出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);
}
輸出:

其實,我們可以認為只有在定義從LINQ查詢返回的數據時才使用var關鍵字。
自動屬性
我們知道.NET語言推薦使用類型屬性來封裝私有數據字段,而不是 使用GetXXX()和SetXXX()方法。因為.NET基類庫總是使用類型屬性而不是傳統的訪問和修改方法,因此使用屬性可以獲得與.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; }
}
}
雖然定義屬性不難,但如果屬性只是賦值和返回值,對次定義字段和屬性也很麻煩,特別是在類屬性很多的情況下。為了簡化這種簡單的數據字段封裝的過程,C# 3.0提供了自動屬性語法。現在,上面的Person可以定義成如下形式:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Level { get; set; }
}
定義自動屬性時,我們只需要指定訪問修飾符、數據類型、屬性名稱和空的get/set作用域。在編譯時,會使用自動生成的私有支持字段以及get/set邏輯的正確實現。
需要注意的是,定義自動屬性時,必須同時提供get和set關鍵字,因此不能定義只讀或者只寫的自動屬性。
匿名類型
作為一個面向對象的程序員,我們知道如何定義類來表達一個給定的編程實體。當我需要一個在項目之間重用的類型時,我們通常創建一個C#類,為該類提供必需的一系列屬性、方法和事件等。但有時候,我們可能需要定義類來封裝一些相關數據,而不需要任何相關聯的方法、事件。并且,給類不需要在項目間重用。盡管如此,我們還是得定義一個“臨時”類,雖然工作不是很復雜,但是如果需要定義類來封裝很多數據成員的話,那么將消耗你大量的勞動時間。我想,大家都不會希望把編程變成一項機械運動吧。
C# 3.0提供的匿名類型正是為了上述任務而生,匿名類型是匿名方法的自然延伸,可以幫助我們輕松的完成上面的工作。
定義一個匿名類型時,使用新的關鍵字var和之前介紹的對象初始化語法,如下示例:
static void TestAnonymousType()
{
// 構造一個匿名對象表示一個雇員
var worker = new { FirstName = "Vincent", LastName = "Ke", Level = 2 };
// 顯示并輸出
Console.WriteLine("Name: {0}, Level: {1}", worker.FirstName + "" + worker.LastName, worker.Level);
}
使用上述代碼來構建匿名對象時,C#編譯器會在編譯時自動生成名稱唯一的類。因為這個類的名字在C#中是不可見的,所以必需使用var關鍵字來使用隱式類型化。另外,我們需要通過對象初始化語法來定義一系列屬性來封裝各個數據。
匿名類型的內部表示
所有的匿名類型都自動繼承自System.Object,我們可以在隱式類型話的worker上面調用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()
{
// 構造一個匿名對象表示一個雇員
var worker = new { FirstName = "Vincent", LastName = "Ke", Level = 2 };
ReflectAnonymousType(worker);
}
結果如下:

上例中,worker的類型是<>f__AnonymousType0`3(各版本之中可能會有所不同),匿名類型的類型名完全由編譯器決定。更重要的是,使用對象初始化語法定義的每一個名稱/值對被映射為同名的只讀屬性以及被封裝的私有數據成員。
方法ToString()和GetHashCode()的實現
從上面可以看到,匿名類型直接了System.Object,并且重寫了Equals()、GetHashCode()、ToString()方法。其中ToString()根據每一個名稱/值對,生成并返回一個字符串,見上圖。
GetHashCode()的實現使用每一個匿名類型的成員變量來計算散列值。當且僅當兩個匿名類型有相同的屬性別且被賦予相同的值時,就會產生相同的散列值,這樣,匿名類型就可以很好的和Hashtable容器一起工作。
匿名類型的相等語義
編譯器重寫的Equals()在判斷對象時使用了基于值的語義,但編譯器并沒有重載(==和!=)相等運算符,因此使用==比較兩個匿名對象時,是基于引用的語義!”==”比較引用是對所有類的默認行為。如下例:
static void AnonymousTypeEqualityTest()
{
// 構建兩個匿名類型,擁有相同的名稱/值對
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");
主站蜘蛛池模板: 久久天天躁狠狠躁夜夜婷 | 亚洲天堂视频网| 最新中文字幕国产精品| 色偷偷亚洲女人天堂观看| 国产成人综合色就色综合| 国精一二二产品无人区免费应用| 亚洲熟妇无码av另类vr影视| 91精品人妻中文字幕色| 少妇真人直播免费视频| 日本污视频在线观看| 激情内射亚洲一区二区三区| 四虎影院176| 亚洲无线码中文字幕在线| 极品少妇无套内射视频| 鹰潭市| 国产肥臀视频一区二区三区| 欧美日韩精品一区二区三区高清视频 | 中文字幕日韩有码第一页| 一区二区不卡国产精品| 高雄市| 蜜桃久久精品成人无码av| 蜜桃视频一区二区在线观看| 台江县| 成人国产精品免费网站| 国产成人精品一区二区| 无码囯产精品一区二区免费| 人妻少妇88久久中文字幕| 色婷婷婷丁香亚洲综合| 无码人妻精品一区二区三区蜜桃| 国产午夜精品福利在线观看| 久久中文字幕无码一区二区| 日本深夜福利在线观看| 成人精品一区二区三区四| 久久88香港三级台湾三级播放| 中文字幕日韩精品有码| 精品精品亚洲高清a毛片| 无码高潮爽到爆的喷水视频| 日韩一区二区三区无码a片| 蜜芽久久人人超碰爱香蕉 | 国产精品69人妻我爱绿帽子| 97久久综合亚洲色hezyo|
