-語法糖,意指那些沒有給計算機語言添加新功能,而只是對人類來說更“sweet”的語法,意在使得編程風格更易讀。C#2.0,3.0發布的新特性,除了泛型不是語法糖,其他所有的新特性幾乎都是語法糖。
-但初學者往往因為不了解這些語法糖,從而在閱讀代碼的時候,難以理解其真正的運作方式。最著名的莫過於Lamda表達式,第一次看到它,很多人都會頂個大問號把。。。
-文章前面會伴隨一些讓人看着想吐槽的代碼,請大家自行河蟹。然后我們會介紹一些語法糖來潤色一下,方便初學者們知道這些語法糖的原始意義。
我們來做一個List<T>類的練習。我會寫一個很蛋疼的例子(盡量不用語法糖,當然這很難避免)。首先我定義了一個學生類
public class Student { private string num; public string Num { get { return num; } } private string name; public string Name { get { return Name; } } public Student(string num, string name) { this.num = num; this.name = name; } public override string ToString() { return num + ":" + name; } }
現在練習下List<T>的FindAll()方法,它的聲明如下
public T FindAll(Predicate<T>match)
FindAll方法把Predicate<T>作為參數,Predicate<T>是一個委托,它引用一個謂詞方法-返回布爾值的方法。如果謂詞返回true,表示有一個匹配。
所以我寫了一個FindStudent類來定義謂詞。這個方法用要搜索的學生的學號來初始化,FindPredicate()接收一個student對象,比較student對象的學號與構造函數中設置的學號,返回true or false。
public class FindStudent //修正於2010/4/20 感謝 Terry_Huang和 Jack Afa指正 { private string num name; public FindStudent(string num Name) { this.num = num;
this.name = Name; } public bool FindPredicate(Student student) { return student.Name == name; } }
最后在一個控制台程序里搜索名字叫John的學生。
class Program { static void Main(string[] args) { List<Student> Students = new List<Student>(); Students.Add(new Student("001", "John")); Students.Add(new Student("002", "Marry")); Students.Add(new Student("003", "John")); FindStudent finder = new FindStudent("John"); foreach (var student in Students.FindAll(new Predicate<Student>(finder.FindPredicate))) { Console.Write(student); } } }
有沒有人看到這已經扛不住了呢,特別是對FindStudent類和FindAll的冗長的用法?
下面我們來一點一點的潤色把。
甜死你1號-自動屬性:只需在定義一個類時指定屬性名,C#3.0編譯器將自動實現相應的內部的private變量,並自動生成set訪問器和get訪問器。
甜死你2號-對象初始值設定項:在自動屬性的前提下,在創建對象時可以對任何可訪問的屬性或字段賦值,而不需要顯示的調用構造函數。
基於這兩個特性,我們來修改一下Student類:
public class Student { public string Num { get; set; } public string Name { get;set; } public override string ToString() { return Num + ":" + Name; } }
自動屬性會自動生成私有變量,不需要顯示的聲明,並且可以直接通過對象初始值設定項對可訪問的屬性和字段賦值,構造函數也不是必須的。呃,是不是清爽多了。
甜死你3號-匿名方法 : 我們之前必須首先聲明方法后才能在委托中使用,C#2.0引入匿名方法,可以delegate{ //dosomething}的形式以一種“內聯”的方式來編寫方法代碼,將代碼直接與委托實例相關聯,從而使得委托實例化的工作更加直觀和方便。
有些時候我們需要臨時保存一些運算的中間結果,我們常常會去聲明一個新的類型,以方便保存這些中間結果。表面上 看起來這很正常,而細想之后就會發現,這個新類型只服務於這個函數,其它地方都不會再使用它了,就為這一個函數而去定義一個新的類型,確實有些麻煩,比如FindStudent類。
有了匿名方法,FindStudent類已經沒有存在的意義了(大快人心?),因為自動屬性的關系,我們可以直接訪問屬性,並且用匿名方法來代替謂詞。
插播廣告:
甜死你4號-集合初始值設定項:我們除了可以像初始化數組一樣,初始化對象之外,同樣對於集合也可以不用再重復的Add來增加集合項了,我們來看新的Main函數:
static void Main(string[] args) { List<Student> Students = new List<Student>() { new Student(){ Num="001", Name="John"},//使用對象初始值設定項初始化對象,代替構造函數 new Student(){ Num="002", Name="Marry"}, new Student(){ Num="003", Name="John"} };//使用集合初始值設定項初始化集合,不用重復調用Add方法 foreach (var student in Students.FindAll(delegate(Student student) { return student.Name == "John"; }))//使用匿名方法完成FindStudent類的功能 { Console.WriteLine(student); } Console.ReadKey(); }
是不是看着順眼多了。不過foreach這句還是有點不順眼。腫么辦,我們只好開大招了。
甜死你終結者號-Lamda表達式:它是升級版的匿名方法,其作用是簡化匿名方法的寫法。寫法(形參列表)=>{函數體}
拿delegate(Student student) { return student.Name == "John"; }這個匿名方法為例,我們的參數就只有student一個,形參我們就使用s代替。
Lamda表達式就是 s=>s.Name=="John"。
順便我們用一下List<T>的ForEach方法。
又一條廣告:
甜死你路人號-匿名類型: 使用var關鍵字來進行類型聲明,而不需要顯示的聲明類型,具體的類型將由編譯器來推斷。
最終的Main函數就是:
static void Main(string[] args) { List<Student> Students = new List<Student>() { new Student(){ Num="001", Name="John"},//使用對象初始值設定項初始化對象,代替構造函數 new Student(){ Num="002", Name="Marry"}, new Student(){ Num="003", Name="John"} };//使用集合初始值設定項初始化集合,不用重復調用Add方法 var John = Students.FindAll(s => s.Name == "John");//使用var聲明匿名類型,其實John是個List<Student> John.ForEach(j => Console.WriteLine(j));//使用Lamda表達式 Console.ReadKey(); }
這樣的代碼看着就很舒服了。
當然語法糖還有很多,如文章開頭所說,C#的新特性大多是語法糖。當然還有一些其他的語法糖,比如三元運算符Test?expression1:expression2就有一個語法糖,寫作
expression1??expression2 2選1,expression1為null則執行expression2。反之執行expression1。
歡迎大家補充,這里就不多做介紹了。
--------------------------------------------我是分割線------------------------------------------------
語法糖能夠增加程序的可讀性,但凡事都有兩面性。比如你需要在屬性的get方法中寫一些邏輯,顯然自動屬性就不適用了。所以不必強求。
咱別硬吃把牙吃壞了。。。