前面两篇C#语法主要是回顾委托相关的。这篇主要回顾了泛型。算法
1、为何要有泛型?数组
咱们在写一些方法时可能会方法名相同,参数类型不一样的方法,这种叫作重载。若是只是由于参数类型不一样里面作的业务逻辑都是相同的,那可能就是复制粘贴方法,改变参数类型,例如一些排序算法,int、float、double等类型的排序,参数数组存的数据类型不同,还有像根据索引找到List集合中的对象。可能这个对象是Person、Dog等对象,这样方法改变的只是参数类型,那就是能不能写一个方法,传递不一样的参数类型呢?因而乎有了泛型。函数
2、什么是泛型?ui
泛型经过参数化类型来实如今同一份代码上操做多种数据类型。例如使用泛型的类型参数T,定义一个类Stack<T>,能够用Stack<int>、Stack<string>或Stack<Person>实例化它,从而使类Stack能够处理int、string、Person类型数据。这样能够避免运行时类型转换或封箱操做的代价和风险,相似C++的模板。泛型提醒的是将具体的东西模糊化,这与后面的反射正好相反。spa
3、泛型democode
1.泛型类orm
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Generic { public class Stack<T> { private T[] s; int pos; public Stack(int size) { s = new T[size]; pos = 0; } public void Push(T val) { s[pos] = val; pos++; } public T Pop() { pos--; return s[pos]; } public void display() { Console.WriteLine("Stack Push:"); foreach (T i in s) { Console.WriteLine(i); } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Generic { class Program { static void Main(string[] args) { Stack<int> s1 = new Stack<int>(2); s1.Push(1); s1.Push(2); s1.display(); Console.WriteLine("Stack Pop:"); Console.WriteLine(s1.Pop()); Console.WriteLine(s1.Pop()); Stack<string> s2 = new Stack<string>(2); s2.Push(@"One"); s2.Push(@"Two"); s2.display(); Console.WriteLine("Stack Pop:"); Console.WriteLine(s2.Pop()); Console.WriteLine(s2.Pop()); Console.ReadLine(); } } }
上面定义了一个泛型类,主要是维护一个栈,栈里存放T类型的数据,在demo中能够定义int、string类型的栈,这样就很方便,使用一套代码能够维护多种数据类型。若是没有这个可能还要维护double、float等代码。对象
2.泛型方法blog
上面是泛型类,主要是在类层面进行参数化,咱们还能够在更小的层面,在函数上进行泛型化。排序
咱们能够在上面Mina类中定义一个静态的泛型方法,用来获取找数值在数组中的位置。
public static int Find<T>(T[] valus, T val) { for (int i = 0; i < valus.Length; i++) { if (valus[i].Equals(val)) { return i; } } return -1; }
咱们能够用上面的方法来查找int数组、float数组
int val = 4; int pos = Find<int>(new int[] {1,2,3,4,5 },val); Console.WriteLine(string.Format("int Pos:{0}",pos)); float val1 = 4; pos = Find<float>(new float[] { 1, 2, 3, 4, 5 }, val1); Console.WriteLine(string.Format("float Pos:{0}", pos)); Console.ReadLine();
下面是两个demo的输出
4、约束
约束是指对泛型类型参数施加限制,用于限制能够传递到该类型参数的类型种类。若是使用某个约束不容许的类型来实例化,则会产生编译时错误。约束使用where关键字指定。
约束有4种类型:
1.基类约束
指定编译器泛型类型参数必须派生自特定基类
修饰符 class 类名<类型参数列表> where 类型参数:基类名
{ 类体}
2.接口约束
指定编译器泛型类型参数必须派生自特定接口
修饰符 class 类名<类型参数列表> where 类型参数:接口名
{ 类体}
3.默认构造函数约束
指示编译器泛型类型参数公开了默认的公共构造函数(不带任何参数的公共构造函数)
修饰符 class 类名<类型参数列表> where 类型参数:new ()
{ 类体}
4.引用/值类型约束
指示编译器泛型类型参数必须是引用类型或值类型
修饰符 class 类名<类型参数列表> where 类型参数:struct(或class)
{ 类体}
能够对同一类型参数使用多个约束,而且约束自身能够也能够是泛型类型,多个约束之间用逗号隔开。
5、泛型委托
泛型委托主要是想讲一下Action<T>和Func<TResult>两个委托,由于这两个在Linq中是常常见到的。
Action<T>只能委托必须是无返回值的方法
Fun<TResult>只是委托必须有返回值的方法
无论是否是泛型委托,只要是委托委托那能用Lamdba表达式,由于无论Lamdba表达式仍是匿名函数其实都是将函数变量化。
下面简单的来作的demo说下两个的用法,这个会了基本linq会了一半了。
Action<string> action = s => { Console.WriteLine(s); }; action("cuiyanwei"); Func<int, int, int> func = (int a, int b)=>{ return a + b; }; int result=func(1, 2); Console.WriteLine("sum:{0}",result); Console.ReadLine();
上面其实都是将函数作为变量,这也是委托的思想。action是实例化了一个只有一个字符串参数没有返回值得函数变量。func是实例化了一个有两个int类型的参数返回值为int的函数变量。下面来看下输出结果:
咱们能够看到经过Lamdba表达式和泛型的结合,算是又方便了开发者们,更加方便实用。
最后在这传统佳节情人节,祝各位单身狗(包括我)早日脱单,不过说实话今天我仍是挺高兴的,朋友玩失踪又出现了,这算是节日最大的快乐吧。