1、ASP.NET MVC入门到精通——新语法
??? 本系列目錄:ASP.NET MVC4入門到精通系列目錄匯總
在學習ASP.NET MVC之前,有必要先了解一下C#3.0所帶來的新的語法特性,這一點尤為重要,因為在MVC項目中我們利用C#3.0的新特性將會大大的提高我們的開發效率,同時,在MVC項目中你將到處可以看到C#3.0新特性的身影。其本質都是“語法糖”,由編譯器在編譯時轉成原始語法。
目錄
- 自動屬性
- 隱式類型 var
- 參數默認值 和 命名參數
- 對象初始化器與集合初始化器
- 匿名類& 匿名方法
- 擴展方法
- 系統內置委托:Func / Action
- Lambda表達式
- 標準查詢運算符(SQO)
- LINQ
自動屬性
這個概念很簡單,其簡化了我們在.NET的時候手寫一堆私有成員+屬性的編程方式,我們只需要使用如下方式聲明一個屬性,編譯器會自動生成所需的成員變量。
回顧傳統屬性概念,屬性的目的:封裝字段,控制?1.讀寫權限?及?2.字段的訪問規則(如:年齡范圍)。但平時,主要是用來封裝讀寫權限。
?基本用法:
public class User{public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }public Address Address { get; set; }}在C#3.0之前,我們是這樣來實現屬性的:
private int id;public int Id{get{return id;}set{id = value;}}思考:
用自動屬性的話程序員寫的代碼少了,機器做的事情就多了,那我們到底要不要使用它?
如果是針對讀寫權限的封裝,就推薦使用,因為它是在編譯的時候產生了負擔,并不是在運行的時候。(不會影響客戶運行程序時的效率!)
但是編譯生成的代碼也有一個顯而易見的缺點,語法太完整,編譯后的程序集會比較大。
隱式推斷類型
這個名稱可能對你很陌生,但是var這個關鍵字應該都用過,在C#中使用var聲明一個對象時,編譯器會自動根據其賦值語句推斷這個局部變量的類型。賦值以后,這個變量的類型也就確定而不可以再進行更改。另外var關鍵字也用于匿名類的聲明。
應用場合:var主要用途是表示一個LINQ查詢的結果。這個結果可能是ObjectQuery<>或IQueryable<>類型的對象,也可能是一個簡單的實體類型的對象。這時使用var聲明這個對象可以節省很多代碼書寫上的時間。
var customer = new Customer();var隱式類型的限制
1.被聲明的變量是一個局部變量,而不是靜態或實例字段;
2.變量必須在聲明的同時被初始化;編譯器要根據初始化值推斷類型
3.初始化不能是一個匿名函數;
4.初始化表達式不能是 null;
5.語句中只聲明一次變量,聲明后不能更改類型;
6.賦值的數據類型必須是可以在編譯時確定的類型;
參數默認值 和 命名參數
?? public class Dog??? {
?????? public void Say(string name = "jf", int age=1)
??????? {
??????????? Console.WriteLine(name + "," + age);
??????? }
??? } class Program{static void Main(string[] args){Dog _dog = new Dog();_dog.Say();_dog.Say("haha");_dog.Say("wuwu", 2);}}
運行結果:
如果要name使用默認值,age給值怎么辦?
_dog.Say(age: 3); //輸入結果:jf,3
對象集合初始化器
在.NET2.0中構造一個對象的方法一是提供一個重載的構造函數,二是用默認的構造函數生成一個對象,然后對其屬性進行賦值。在.NET3.5/C#3.0中我們有一種更好的方式來進行對象的初始化。那就是使用對象初始化器。這個特性也是匿名類的一個基礎,所以放在匿名類之前介紹。需要注意的是,它最終還是離不開構造函數,它其實是使用默認的構造函數生成了一個對象。
對象初始化:
User user = new User { Id = 1, Name = "Zouqj", Age = 26 };集合初始化:
創建并初始化數組:
string[] array = { "aaa", "bbb" };匿名類
有了前文初始化器的介紹,匿名類就很簡單了。我們可以使用new {?object initializer?}或new[]{ object, …}來初始化一個匿名類或不確定類型的數組。匿名類的對象需要使用var關鍵字聲明。示例代碼:
var p = new { Id = 1, Name = " Zouqj ", Age = 26 };//屬性名字和順序不同會生成不同類在編譯后會生成一個【泛型類】,包含:
a. 獲取所有初始值的構造函數,順序與屬性順序一樣;
b.公有的只讀屬性,屬性不能為null/匿名函數/指針;
c.屬性的私有只讀字段;
d.重寫的Equals,GetHashCode,ToString()方法
用處:
a.避免過度的數據累積
b.為一種情況特別進行的數據封裝
c.避免進行單調重復的編碼
應用場合:當直接使用select new {?object initializer?}這樣的語法就是將一個LINQ查詢的結果返回到一個匿名類中。
注意:
1.?當出現“相同”的匿名類的時候,編譯器只會創建一個匿名類
2.?編譯器如何區分匿名類是否相同?
根據:屬性名,屬性值(因為這些屬性是根據值來確定類型的),屬性個數,屬性的順序。
3、匿名類的屬性是只讀的,可放心傳遞,可用在線程間共享數據
匿名方法
函數式編程的最大特點之一:把方法作為參數和返回值。 DGShowMsg -> MulticastDelegate(intPtr[]) -> Delegate(object,intPtr)
匿名方法:編譯后會生成委托對象,生成方法,然后把方法裝入委托對象,最后賦值給 聲明的委托變量。
匿名方法可以省略參數:編譯的時候 會自動為這個方法 按照 委托簽名的參數 添加參數
擴展方法
擴展方法的本質:編譯時,直接將 str.WriteSelf(2015) 替換成 StringUtil.WriteSelf(str,2015);
想為一個類型添加一些成員 , 怎么辦?
擴展方法:
測試:
??? string str="中國釣魚島";
??? str.WriteSelf(2015);
本質就是靜態方法
編譯器認為一個表達式是要使用一個實例方法,但沒有找到,就會檢查導入的命名空間和當前命名空間里所有的擴展方法,并匹配到適合的方法.
注意:1.實例方法優先于擴展方法(允許存在同名實例方法和擴展方法)2.可以在空引用上調用擴展方法!3.可以被繼承4.并不是任何方法都能作為擴展方法使用,必須有特征:
它必須放在一個非嵌套、非泛型的靜態類中(的靜態方法);
它至少有一個參數;
第一個參數必須附加 this 關鍵字;
第一個參數不能有任何其他修飾符(out/ref)
第一個參數不能是指針類型
看看這兩個接口的方法:IEnumerable<T> ,IQueryable<T>
系統內置委托:Func / Action
委托使用可變性 :
Action<object> test=delegate(object o){Console.WriteLine(o);}; Action<string> test2=test; Func<string> fest=delegate(){return Console.ReadLine();}; fest2=fest;public delegate void Action(); public delegate bool Predicate<in T>(T obj); public delegate int Comparison<in T>(T x, T y);協變指的是委托方法的返回值類型直接或間接繼承自委托簽名的返回值類型,逆變則是參數類型繼承自委托方法的參數類型
System.Func 代表有返回類型的委托
public delegate TResult? Func<out TResult>();
public delegate TResult? Func<in T, out TResult>(T arg);
......
注:輸入泛型參數-in 最多16個,輸出泛型參數 -out 只有一個。
System.Action 代表無返回類型的委托
public delegate void Action<in T>(T obj);??? //list.Foreach
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
......
注:參數最多16個
System.Predicate<T> 代表返回bool類型的委托?? - 用作執行表達式
public delegate bool Predicate<in T>(T obj);? //list.Find
System.Comparison<T> 代表返回int類型的委托? - 用作比較兩個參數的大小
public delegate int Comparison<in T>(T x, T y); //list.Sort
為什么要定義這么多簡單的委托? 方便!
Lambda表達式
?????Lambda表達式的本質就是匿名函數,Lambda表達式基于數學中的λ演算得名,直接對應于其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。“Lambda 表達式”是一個匿名函數,它可以包含表達式和語句,并且可用于創建委托或表達式樹類型。
Lambda 表達式的運算符 =>,該運算符讀為“goes to”。
=> 運算符具有與賦值運算符 (=) 相同的優先級
Lambda的基本形式:(input parameters) => expression
只有在 Lambda 有一個輸入參數時,括號才是可選的;否則括號是必需的。 兩個或更多輸入參數由括在括號中的逗號分隔: (x, y) => x == y
有時,編譯器難于或無法推斷輸入類型。 如果出現這種情況,您可以按以下示例中所示方式顯式指定類型: (int x, string s) => s.Length > x
使用空括號指定零個輸入參數: () => SomeMethod()
最常用的場景:Ienumable和Iqueryable接口的Where<>(c=>c.Id>3)
下列規則適用于 Lambda 表達式中的變量范圍:
捕獲的變量將不會被作為垃圾回收,直至引用變量的委托超出范圍為止。
在外部方法中看不到 Lambda 表達式內引入的變量。
Lambda 表達式無法從封閉方法中直接捕獲 ref 或 out 參數。
Lambda 表達式中的返回語句不會導致封閉方法返回。
Lambda 表達式不能包含其目標位于所包含匿名函數主體外部或內部的 goto 語句、break 語句或 continue 語句。
Lambda表達式縮寫推演
例子:
delegate int AddDel(int a,int b); //定義一個委托#region lambda AddDel fun = delegate(int a, int b) { return a + b; }; //匿名函數//Console.WriteLine(fun(1, 3));//lambda 參數類型可以進行隱式推斷,可以省略類型 lambda本質就是匿名函數AddDel funLambda = ( a, b) => a + b;List<string> strs = new List<string>() { "1","2","3"};var temp = strs.FindAll(s => int.Parse(s) > 1);foreach (var item in temp){Console.WriteLine(item);}//Console.WriteLine(funLambda(1,3)); #endregionstatic void Main(string[] args)
??????? {?????? ?
??????????? List<int> nums = new List<int>() { 1,2,3,4,6,9,12};
??????????? //使用委托的方式
??????????? List<int> evenNums = nums.FindAll(new Program().GetEvenNum);
??????????? foreach (var item in evenNums)
??????????? {
??????????????? Console.WriteLine(item);
??????????? }
??????????? Console.WriteLine("使用lambda的方式");
??????????? List<int> evenNumLamdas = nums.FindAll(n => n % 2 == 0);
??????????? foreach (var item in evenNumLamdas)
??????????? {
??????????????? Console.WriteLine(item);
??????????? }
??????????? Console.ReadKey();
??????????? //nums.FindAll(
??????? }
??????? public bool GetEvenNum(int num)
??????? {
??????????? if (num % 2 == 0)
??????????? {
??????????????? return true;
??????????? }
??????????? return false;
}??????
標準查詢運算符(SQO)
標準查詢運算符:定義在System.Linq.Enumerable類中的50多個為IEnumerable<T>準備的擴展方法,這些方法用來對它操作的集合進行查詢篩選.
- 篩選集合Where:需要提供一個帶bool返回值的“篩選器”,從而表明集合中某個元素是否應該被返回。
- 查詢投射,返回新對象集合 IEnumerable<TSource> Select()
- 統計數量int Count()
- 多條件排序 OrderBy().ThenBy().ThenBy()
- 集合連接 Join()
- ......
延遲加載:Where
即時加載:FindAll
SQO缺點:語句太龐大復雜
LINQ
C#3.0新語法:查詢表達式,和SQL風格接近的代碼
IEnumerable<Dog> list = from dog in dogs where dog.Age>5 //let d=new{Name=dog.Name} orderby dog.Age descending select dog; //select new{Name=dog.Name}以"from"開始,以"select 或 group by子句"結尾。輸出是一個 IEnumerable<T> 或 IQueryable<T> 集合;
注:T 的類型 由 select 或 group by 推斷出來。
LINQ分組:
IEnumerable<IGrouping<int, Dog>> listGroup = from dog in listDogs where dog.Age > 5 group dog by dog.Age;遍歷分組:
foreach (IGrouping<int, Dog> group in listGroup) {Console.WriteLine(group.Key+"歲數:");foreach (Dog d in group){Console.WriteLine(d.Name + ",age=" + d.Age);} }最后:LINQ 查詢語句 編譯后會轉成 標準查詢運算符
此外,我建議大家多使用reflector工具來查看C#源碼和IL語言,reflector就像一面照妖鏡,任何C#語法糖在它面前都將原形畢露。
總結
以上是生活随笔為你收集整理的1、ASP.NET MVC入门到精通——新语法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DIV+CSS实战(四)
- 下一篇: Plyr – 简单,灵活的 HTML5