前言
開始時學的是C#2.0而且沒有學完全。工作後,不是在忙著趕項目,就是對各種技術嘗嘗鮮,而語言的學習卻沒有什麼進步。直到半年前開始入門Python(純粹愛好,斷斷續續的學著)才發現——原來編程還可以這樣!原來代碼還可以這樣寫!
沉溺於各種設計模式、架構、新鮮技術
回眸一望
忽然發現
她
依然如此優雅
甚至
更勝從前!
目標
補完C# 2.0 3.0的新特性,然後在研究研究4.0。本章先從泛型開始溫習一下。
參考連結
詳細讀完這些文章,你就不用看我寫的了!如有不明請往下,還是不明請留言,大家相互討論。
C#泛型簡介
Predicate泛型委派
Func(T,TResut)委託
泛型委派(C#編程指南)
走進Linq-Linq大觀園
C++ 範本和 C# 泛型間的區別
泛型
有句經典的等式: 演算法+ 資料結構 = 程式!寫程式總會遇到一些演算法相同(處理方法相似),但資料結構不同的情況。難道就為了把int 改成 double 、Struct或Class A ,而把代碼再打一遍嗎?
你很勤快,不在乎多敲一次代碼?不,程式員應該很懶!讓機器幫我們去做吧,於是我們有了泛型——Class Stack<T>。
C#2.0 引入了泛型它類似於C++的模板(都是C 一家親嘛,另外推薦一篇利用C++模板來列印質數的博文,它的厲害之處在於利用c++模板的特性,在編譯時間計算出質數而不是運行時 ——質數列印),但是在實現和功能方面還是存在差異的。我們可以這樣定義泛型
1 /// <summary>
2 /// 在類上定義
3 /// </summary>
4 /// <typeparam name="T"></typeparam>
5 public class Stack<T>
6 {
7 public void Push(T value)
8 { }
9 }
10
11 /// <summary>
12 /// 在方法裡
13 /// </summary>
14 public class Stack
15 {
16 public void Push<T>(T value)
17 { }
18 public T Pop<T>(T value1, T value2) { return value1; }
19 }
20 /// <summary>
21 /// 錯誤案例,因為 預留位置 還沒聲明,就使用了。
22 /// </summary>
23 //public class StackT
24 //{
25 // public void Push(T value)
26 // { }
27 //}
28
29 //委託
30 public delegate TResult Add<T,TResult>(T value);
其實T 就是一個預留位置(為啥是T?當然你也可以是V、R、Y,這得從它哥哥說起),個人認為把泛型裡的T理解為預留位置是最直接的。先聲明<T> ,然後就可以在該泛型裡,直接使用這個預留位置T了。編譯器會根據 調用泛型時指定的預留位置T的類型,來替換 或推斷出對應的類型。
//聲明
public class Stack<T>
{
//在 Stack 的範圍裡 可以調用。
public void Push(T value)
{ }
public void Pop<V>(statck<V> s, params V[] p){}
}
在使用 class Stack 時 必須指定T 預留位置是什麼,編譯器就能推斷出 Push(T)的類型了。而Pop 裡的V是另一個預留位置,在使用時需要指定。
Stack<int> stack = new Stack<int>();
stack.Pop<string>("nihao ", "sdfsdf", "sdfsdf", "sdfsdfvwevwwve");
其實這個例子除了表明一些文法外,沒什麼意義。
泛型委派
委託也可以定義泛型,將參數一般化。在.net 3.5 裡為我們定義了幾個常見的泛型委派Predicate<> Func<> Action<> 等幾個泛型。 有了這幾個常用的委託我們寫起代碼來就更加方便了。
View Code
class Program
{
static void Main(string[] args)
{
Func<string, string> test1 = IsTooLong;
Func<string, string> test2 = delegate(string str)
{
if (str.Length > 10)
{
return "Too long";
}
else
{
return "ok";
}
};
Func<string, string> test3 = (str) => str.Length > 10 ? "Too long" : "ok";
Console.WriteLine(test3("sodiinbgweoeinbowevw"));
Console.Read();
}
static string IsTooLong(String value)
{
if (value.Length > 10)
{
return "Too long";
}
else
{
return "ok";
}
}
}
代碼使用 Func<> 定義了3個有傳回值的委託, 然後再將委託的運行結果輸出,如果字串的長度大於10 則輸出“Too Long”。
test1裡 也可以寫成“test1 = new Func<string, string>(IsTooLong);” ,但是直接賦予 =IsTooLong更簡潔不是嗎? 這得歸功於編譯器的委託推理,它能夠推斷出我們分配到委託的類型,並驗證該方法是否與簽名相匹配。
test2 用到了 匿名方法
test3 則是使用了lambda 運算式,這個是不是更簡潔。
後記
這裡只簡單的介紹一下泛型,詳細的資訊可以查看參考連結。把T 理解為預留位置 就好,編譯器會幫我們替換它的。