一.为何要提出泛型的概念html
咱们在声明对象或者方法中,对象中成员变量的定义或者函数参数都传递都要指定具体的对象类型,可是有的时候参数的类型是变化的,可是实现的功能却又差很少,这个时候咱们就想,是否存在一种东西能够将参数的位置“占住”,当传递具体的对象类型是再用这个类型取替换被占住的位置,这个时候就提出了泛型的概念,是否是有点绕,可是看完下面的例子就清除这里表达的内容了,泛型有多种表现形式,泛型类,泛型方法,泛型集合,泛型委托,能够说不懂泛型就没有真正的了解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
使用泛型集合首先是是加了类型安全,方便编程,泛型集合指定了类型后只能将同类型的参数放入集合,泛型集合最经常使用就是List集合和Dictionary集合,咱们分别看一下这两种集合。spa
A.Lis<T> 泛型集合设计
说到List泛型集合就不得不说ArrayList集合,ArrayList集合在操做是须要进行强制类型,极大的下降了代码处理效率因此,List集合应运而生,让咱们看以下代码作个比较:code
//用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(); }
好的以上就是关于泛型概念的总结,但愿能够帮到有须要的人。
原文出处:https://www.cnblogs.com/Artist007/p/11089085.html