今天下午依舊逃課(大學生就業指導)很操蛋的課程,要是上這課真能給我們指條路也就好了,看着男同學們一個個陽痿早泄,女同學們一個個搔首弄姿,哈哈還是不去了,所以兩年來此類的課程一節都沒上過,於是就寫點東西,此外的可以暫時忽略。
1.首先我們應該知道什么是擴展方法:
-
定義一個靜態類以包含擴展方法。
-
將該擴展方法實現為靜態方法,並使其至少具有與包含類相同的可見性。
-
該方法的第一個參數指定方法所操作的類型;該參數必須以 this 修飾符開頭。
-
在調用代碼中,添加一條 using 指令以指定包含擴展方法類的 命名空間。
-
按照與調用類型上的實例方法一樣的方式調用擴展方法。
好了,概念性的問題我們都知道了,如果你還沒有理解,我們直接寫個簡單的實例:
using System; namespace 擴展方法 { using StringUnit;//添加包含擴展方法類的命名空間 class Program { static void Main(string[] args) { string s1 = "你好"; string s2 = "rohelm!"; string s3 = "["+s1.StringCombine(s2).StringCombine("]"); Console.WriteLine(s3); string s4 = StringPro.StringQuote(s2);//也可以利用靜態方法調用哦 string s5 = s1.StringQuote(); Console.WriteLine(s4.StringCombine(s5)); Console.ReadKey(); } } } namespace StringUnit { static class StringPro//定義一個靜態類以包含擴展方法 { public static string StringCombine(this string str1, string str2)//第一個參數必須以 this修飾符開頭。 { return str1 + str2; } public static string StringQuote(this string str) { return "[" + str + "]"; } } }
我們從上面的代碼中隨意的取出一個進行大概的說明:public static string StringQuote(this string str),第一個參數不是由調用代碼指定的,因為它表示正應用運算符的類型,並且編譯器已經知道對象的類型。也就是這個擴展方法只適用於string類型的運算,因此當我們在Main方法中
s2.StringQuote 當我們一點的時候StringQuote就會自動奔出來,好像是String類內置的一個方法一樣,我們於是可以按照實例方法一樣的方式調用擴展方法,當然我們依然可以使用靜態方法一樣的方式調用擴展方法例如:StringPro.StringQuote(s2)。這里我們要注意擴展方法和類的static以及this關鍵字.
好了我們現在寫一個大家最簡單的匿名方法,知道我要干什么嗎?先寫出來。。。
class Program { static void Main(string[] args) { StringDelegate f=delegate(string s1,string s2){ return s1+s2; }; Console.WriteLine(f("你好","rohelm.X")); Console.ReadKey(); } } delegate string StringDelegate(string s1,string s2);
簡單的都不好意思解釋,好了現在我們簡化匿名函數
StringDelegate f=delegate(string s1,string s2){ return s1+s2; };
於是乎這句變得非常怪異而簡單:
StringDelegate f=(s1,s2)=>{ return s1+s2; };
這就是使用Linq和lambda表達式得出的結果,為什么我們不在需要指出s1,s2的參數類型呢,你覺得編譯器知道他們該是什么類型嗎?
當然,這就是因為我們這個匿名函數是由delegate string StringDelegate(string s1,string s2); 這個委托約束的,因此當然不用猜測就知道
s1,s2的數據類型了,這叫類型推斷,所以省略了似乎多余的參數類型聲明,但是或許對於新手損失可讀性,但是他的確非常強大。其實這個例子很簡單,就是參數類表的優化而已,后面{}內仍舊是方法體。
話到這里我們開始新手的Linq之旅
LINQ是.NET3.5引入的功能,LINQ 通過提供一種跨各種數據源和數據格式使用數據的一致模型,簡化了這一情況。
目的:以統一的方式對數據進行操作。
Linq和擴展方法又有什么聯系?好了我們看一下一個簡單的示例:
1 int[] numbers = new int[7] { 60, 17, 12, 63, 35, 5, 6 }; 2 IEnumerable<int> query = numbers.OrderByDescending(i=>i);//按照降序排列 3 foreach (var i in query) 4 { 5 Console.Write("{0,3}",i); 6 } 7 Console.WriteLine(); 8 IEnumerable<int> query1 = numbers.OrderBy(i => i);//按照升序排列 9 foreach (var i in query1) 10 { 11 Console.Write("{0,3}", i); 12 }
同樣我們在numbers后點的時候會出現
就好像是Array內置的的方法一樣。
現在我們來看他的函數定義的特點:
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer )
由此我們就可以斷定Linq內的函數都其實是擴展方法。
-
獲取數據源。
-
創建查詢。
class IntroToLINQ { static void Main() { // The Three Parts of a LINQ Query: // 1. Data source. int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // 2. Query creation. // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; // 3. Query execution. foreach (int num in numQuery) { Console.Write("{0,1} ", num); } } }
當然沒學LinQ我們依然可以老掉牙的這樣寫:
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; List<int> list = new List<int>(); foreach (int num in numbers) { if (num % 2 == 0) { list.Add(num); } } foreach (int i in list) { Console.Write("{0,1} ", i);
}
現在我們這樣,利用lambda表達式簡化上面的官方示例,只需改一句即可完成相同的功能:
int[] numbers = new int[7] { 60, 17, 12, 63, 35, 5, 6 }; IEnumerable<int> query = numbers.Where(i=>i%2==0);
同時,官方示例內部實行時其實編譯器依舊將其轉化為lambda表達式的形式。
linq 的查詢語句看起來非常像SQL語句,但是和SQL無關。
現在來簡要的介紹一下常用的語句,和同學們一起學習下,我也是剛剛學的,不過了解這些還是皮毛,要深入的要就就要熟練掌握必須花時間去深入研究。
1.查詢表達式必須以 from子句開頭
- from 子句中引用的數據源的類型必須為 IEnumerable、 IEnumerable < T >或一種派生類型(如 IQueryable <T >)。
- 查詢表達式還可以包含子查詢,子查詢也是以 from 子句開頭。
static void Main() { string values = "abcdefasfsafcdekjekyursdjdagghiaaefrxfgs"; var query = from value in values group value by value into repeatGroup//通過使用into標識符,可以對每個組調用 Count 方法 orderby repeatGroup.Count() descending//降序排列 select new { 字符 = repeatGroup.Key, 次數 = repeatGroup.Count() }; //通過select返回匿名類型對象實現返回多列的效果 foreach (var cha in query) { Console.WriteLine(cha.字符 + "=" + cha.次數); } Console.ReadKey(); }
剛好發現一個嵌套的form子句的例子,里面使用let子句來保存臨時變量,也就是句子拆成單詞再返回合適條件的。
1 using System; 2 using System.Linq; 3 class LetSample1 4 { 5 static void Main() 6 { 7 string[] strings = 8 { 9 "A penny saved is a penny earned.", 10 "The early bird catches the worm.", 11 "The pen is mightier than the sword." 12 }; 13 14 var earlyBirdQuery = 15 from sentence in strings 16 let words = sentence.Split(' ') 17 from word in words 18 let w = word.ToLower() 19 where w[0] == 'a' || w[0] == 'e' 20 || w[0] == 'i' || w[0] == 'o' 21 || w[0] == 'u' 22 select word; 23 24 // Execute the query. 25 foreach (var v in earlyBirdQuery) 26 { 27 Console.WriteLine("\"{0}\" starts with a vowel", v); 28 } 29 30 // Keep the console window open in debug mode. 31 Console.WriteLine("Press any key to exit."); 32 Console.ReadKey(); 33 } 34 }
下面的方法都是IEnumerable<T>的擴展方法:
Average計算平均值;
Min最小元素;
Max最大元素;
Sum元素總和;
Count元素數量;
Concat連接兩個序列;
Contains序列是否包含指定元素;
Distinct取得序列中的非重復元素;
Except獲得兩個序列的差集;
Intersect獲得兩個序列的交集;
First取得序列第一個元素;
Single取得序列的唯一一個元素,如果元素個數不是1個,則報錯
FirstOrDefault 取得序列第一個元素,如果沒有一個元素,則返回默認值;
Linq只能用於范型的序列,IEnumerable<T>,對於非范型,可以用Cast或者OfType
IEnumerable的方法:
Cast<TResult>:由於Linq要針對范型類型操作,對於老版本.Net類等非范型的IEnumerable序列可以用Cast方法轉換為范型的序列。ArrayList l; IEnumerable<int> il = l.Cast<int>();
OfType<TResult>:Cast會嘗試將序列中所有元素都轉換為TResult類型,如果待轉換的非范型序列中含有其他類型,則會報錯。OfType則是只將序列中挑出指定類型的元素轉換到范型序列中。
Linq對於小數據量、對性能要求不高的環節用linq很方便,而且延遲加載機制降低了內存占用,比一般人寫的程序效率都高。