一.爲何要提出泛型的概念編程
咱們在聲明對象或者方法中,對象中成員變量的定義或者函數參數都傳遞都要指定具體的對象類型,可是有的時候參數的類型是變化的,可是實現的功能卻又差很少,這個時候咱們就想,是否存在一種東西能夠將參數的位置「佔住」,當傳遞具體的對象類型是再用這個類型取替換被佔住的位置,這個時候就提出了泛型的概念,是否是有點繞,可是看完下面的例子就清除這裏表達的內容了,泛型有多種表現形式,泛型類,泛型方法,泛型集合,泛型委託,能夠說不懂泛型就沒有真正的瞭解C#,下面讓咱們來開始泛型的學習吧。數組
二.泛型類,泛型方法安全
咱們先舉個例子,咱們定義一個類來模擬入棧出棧操做,咱們操做出棧入棧時要針對各類數據類型,int型,double 型,字符型......總之各類類型都有可能,咱們不可能針對每一個類型都寫一個類來操做出棧入棧,這顯然是不現實的,這個是時候就該泛型大顯身手發時候了,看下面的定義:函數
public class MyStack<T> //多種類型時能夠用T1,T2,T3......來表示 { public T[] objStack; public int _stackPoint; public int _stackSize; public MyStack(int Size) //成員變量通常在初始化的時候都要賦值 { objStack = new T[Size]; _stackSize = Size; _stackPoint = -1; } /// <summary> /// 入棧操做 /// </summary> /// <param name="item"></param> public void Push(T item) //這裏要把T當成一種數據類型 { if (_stackPoint > _stackSize) { return; } else { _stackPoint++; objStack[_stackPoint] = item; } } /// <summary> /// 出棧操做 /// </summary> /// <returns></returns> public T Pop() { if (_stackPoint > 0) { _stackPoint--; return objStack[_stackPoint]; } else { return objStack[0]; } } }
咱們在 public class MyStack<T> 後面加了一個<T>這個時候這個類就變成了一個泛型類,表示一個佔位符,當咱們實例化該類的時候須要傳入具體的數據類型,咱們來看一下泛型類的具體用法:學習
public int[] arrayInt = new int[6]; public string[] arrayStr = new string[6]; MyStack<int> objMyIntStack = new MyStack<int>(6); MyStack<string> objMyStrStack = new MyStack<string>(6);
這樣泛型類就能夠操做int 類型 和 string類型進行出棧入棧操做但代碼卻不須要改動。this
三.泛型集合spa
使用泛型集合首先是是加了類型安全,方便編程,泛型集合指定了類型後只能將同類型的參數放入集合,泛型集合最經常使用就是List集合和Dictionary集合,咱們分別看一下這兩種集合。設計
A.Lis<T> 泛型集合code
說到List泛型集合就不得不說ArrayList集合,ArrayList集合在操做是須要進行強制類型,極大的下降了代碼處理效率因此,List集合應運而生,讓咱們看以下代碼作個比較:對象
//用ArrayList集合來存儲 ArrayList objArrayList = new ArrayList(); Students stu1 = new Students() { Name="小紅",Age=20}; Students stu2 = new Students() { Name = "小明", Age = 30 }; objArrayList.Add(stu1); objArrayList.Add(stu2); Students obj = (Students)objArrayList[0]; Console.WriteLine(obj.Name + obj.Age.ToString()); //這裏須要進行強制類型轉換 Console.ReadLine(); //用List集合來存儲 List<Students> objList = new List<Students>() { new Students(){Name = "小紅",Age=20}, new Students(){Name="小明",Age = 30} }; foreach (var item in objList) { Console.WriteLine(item.Name + "," + item.Age.ToString()); } Console.ReadLine();
除此以外,咱們一直在講泛型集合能夠保證數據安全,和ArrayList相比它的數據到底安全在什麼地方呢,咱們經過下面的例子作進一步說明:
ArrayList objArrayList = new ArrayList(); Students stu1 = new Students() { Name="小紅",Age=20}; Students stu2 = new Students() { Name = "小明", Age = 30 }; Teacher tea1 = new Teacher() { Name = "小剛", Age = 30 }; objArrayList.Add(stu1); objArrayList.Add(stu2); objArrayList.Add(tea1); //Teacher類也能夠添加進來,類型不安全 foreach (var item in objArrayList) { Students obj00 = (Students)item; }
從例子能夠看出ArrayList集合的Add方法參數是object類型,因此Teacher的數據類型也能夠放進去,這顯然不是咱們想要的,可是泛型集合就不同,當佔位符被肯定的數據類型佔用後,別的數據類型就添加不到集合中去。
List集合的經常使用方法,List集合中有不少方法,咱們重點將一下Sort方法,Sort方法有四個重載方法,public void Sort();,public void Sort(Comparison<T> comparison);,
public void Sort(IComparer<T> comparer);,public void Sort(int index, int count, IComparer<T> comparer);咱們直接調用Sort方法是按默認升序排序,假如某個類實現了IComparable接口那麼默認排序就是按照接口中定義的方法來排序,看下面的例子:
//List集合排序 List<int> intList = new List<int>() { 1, 4, 3, 11, 8, 2, 0 }; intList.Sort(); foreach (var item in intList) { Console.WriteLine(item.ToString()); } Console.ReadLine();
輸出結果爲:0,1,2,3......結果爲升序排序
//字符串排序 List<string> objListStr = new List<string>() { "c","a","b"}; objListStr.Sort(); foreach (var item in objListStr) { Console.WriteLine(item); } Console.ReadLine();
輸出結果爲:a,b,c
假如是對象類型呢,默認的排序方法爲升序排序,可是對象之間沒有升序的概念,這個時候該怎麼辦呢,看下面的代碼:
public class Students : IComparable<Students> { public string Name { get; set; } public int Age { get; set; } /// <summary> /// 實現泛型接口 /// </summary> /// <param name="other"></param> /// <returns></returns> public int CompareTo(Students other) { return other.Name.CompareTo(this.Name); } } static void Main(string[] args) { Students stu1 = new Students() { Name = "Mick", Age = 20 }; Students stu2 = new Students() { Name = "Jack", Age = 30 }; List<Students> objList = new List<Students>(); objList.Add(stu1); objList.Add(stu2); objList.Sort(); foreach (var item in objList) { Console.WriteLine(item.Name); } Console.ReadLine(); }
Students類中實現了泛型接口IComparable<T> ,在泛型接口的方法中咱們能夠寫排序的方式,這樣作確實能夠解決對象排序的問題,可是假如咱們的排序條件是變化的,這種方式顯然又不能知足咱們的需求了,讓我i們接着往下探索,如何實現集合對象的動態排序,讓咱們看以下代碼:
/// <summary> /// 按姓名降序排列 /// </summary> public class NameDesc:IComparer<Students> { public int Compare(Students x, Students y) { return y.Name.CompareTo(x.Name); } } /// <summary> /// 按姓名升序排序 /// </summary> public class NameAsc : IComparer<Students> { public int Compare(Students x, Students y) { return x.Name.CompareTo(y.Name); } } /// <summary> /// 按年齡降序 /// </summary> public class AgeDesc:IComparer<Students> { public int Compare(Students x, Students y) { return y.Age - x.Age; } } /// <summary> /// 按年齡升序 /// </summary> public class AgeAsc : IComparer<Students> { public int Compare(Students x, Students y) { return x.Age.CompareTo(y.Age); } }
咱們定義了一個自定義排序類,自定義排序類實現了ICompare接口。
static void Main(string[] args) { Students stu1 = new Students() { Name = "Mick", Age = 20 }; Students stu2 = new Students() { Name = "Jack", Age = 30 }; List<Students> objList = new List<Students>(); objList.Add(stu1); objList.Add(stu2); objList.Sort(new AgeDesc()); //基於接口實現多態的典型應用 foreach (var item in objList) { Console.WriteLine(item.Name); } Console.ReadLine(); }
調用List.Sort的重載方法,這裏基於接口實現了多態,須要好好體會,關於集合的排序咱們還能夠用Linq查詢。
B.Drictionary<> 泛型集合
List集合用索引查找元素的方法顯然沒有辦法知足咱們的實際需求,爲了彌補這個缺陷,咱們引入了字典的概念,說到鍵值對查詢又不得不說說Hashtable,早期鍵值對集合都是用Hashtable類來實現的,後來泛型集合出現後Dictionary泛型集合取代了Hashtable類,讓咱們來看看二者的區別:
//用Hashtable集合 Hashtable objHashtable = new Hashtable(); objHashtable.Add("student1", new Students() { Name = "小王", Age = 20 }); objHashtable.Add("student2", new Students() { Name = "小李", Age = 25 }); Students stu =(Students)objHashtable["student1"]; //須要進行強制類型轉換 //用Dictionary集合 Dictionary<string, Students> objDictionary = new Dictionary<string, Students>(); objDictionary.Add("student1", new Students() { Name = "小王", Age = 20 }); objDictionary.Add("student2", new Students() { Name="小李",Age = 25}); Students myStudent = objDictionary["student1"]; //不須要進行強制類型轉換
從例子能夠看出Hashtable集合操做都是object的類型,在進行對象操做是須要進行強制類型轉換,可是Dictionary卻不同,不須要進行強制類型轉換,因此能夠這樣講Dictionary出現之後能夠徹底替Hashtable。
四.泛型委託
A.自定義泛型委託
static void Main(string[] args) { Mydelegate<int> objMydelegate = Add; Console.WriteLine("結果爲:{0}", objMydelegate(1, 2)); Console.ReadLine(); } static int Add(int i1,int i2) { return i1 + i2; } } public delegate T Mydelegate<T>(T t1, T t2); //自定義泛型委託
以上例子就簡單展現了自定泛型委託的使用方法,可是每次都這這麼定義委託彷佛很不方便,因此微軟的工程師預先給咱們定義好了幾個泛型委託,咱們能夠直接使用,大大提升了使用泛型委託的便捷程度。
B.Func泛型委託的使用
Func是一個帶返回值的泛型委託,func有多個重載版本,須要注意的是func最後一個參數是返回值類型,若是前面有泛型類型的參數,這個參數就是委託方法的形參類型,簡單說func泛型委託就是一個帶返回值的方法簽名,咱們先來看看它的簡單應用:
static void Main(string[] args) { Func<int, int, int> objFunc = (a, b) => { return a + b; }; Console.WriteLine("結果爲:{0}", objFunc(2, 5)); Console.ReadLine(); }
有人會說這樣用彷佛沒什麼意義,咱們調用方法就能夠直接實現功能,幹嗎還要從委託轉一下彷佛畫蛇添足,可是事實並非如此,讓咱們看一下Func的複雜用法。如今提出一個需求,要求計算數組中任意指定開始位和結束位的「算數和」 and 算數積。常規作法是:
static int GetSum(int[] nums, int from, int to) { int result = 0; for (int i = from; i <= to; i++) { result += nums[i]; } return result; } static int GetMulti(int[] nums, int from, int to) { int result = 1; for (int i = from; i <= to; i++) { result *= nums[i]; } return result; }
寫兩個方法,分別計算和與積,可是還有別的實現方法麼,答案是確定的:
static void Main(string[] args) { int[] nums = { 1, 2, 10, 4, 5, 6, 7, 8, 9 }; Console.WriteLine("數組前三個元素的和爲:{0}", CommonMethod((a, b) => { return a + b; }, nums, 0, 3)); Console.WriteLine("數組前三個元素的積爲:{0}", CommonMethod((a, b) => { return a * b; }, nums, 0, 3)); Console.ReadLine(); } static int CommonMethod(Func<int, int, int> com, int[] nums, int a, int b) { int result = nums[a]; for (int i = a + 1; i < b; i++) { result = com(result, nums[i]); } return result; }
其實這裏也體現了委託的本質,委託原本就是爲了把方法當成參數傳遞而設計的。
C.Action泛型委託
Action泛型委託和func泛型委託差很少,只不過Action是不帶返回值的方法的簽名,看下面的例子咱們就能夠了解Action泛型委託的用法:
static void Main(string[] args) { Action<string> objAction = (a) => { Console.WriteLine(a); }; objAction("Hello C#"); Console.ReadLine(); }
D.Predicate泛型委託
Predicate<T>委託定義以下:
public delegate bool Predicate<T>(T obj);
解釋:此委託返回一個bool值的方法
在實際開發中,Predicate<T>委託變量引用一個「判斷條件函數」,
在判斷條件函數內部書寫代碼代表函數參數所引用的對象應該知足的條件,條件知足時返回true
看下面的例子:
static void Main(string[] args) { List<int> objList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; List<int> resultList = objList.FindAll((s) => { return s > 2; }); //Predicate委託 foreach (var item in resultList) { Console.WriteLine(item); } Console.ReadLine(); }
好的以上就是關於泛型概念的總結,但願能夠幫到有須要的人。